x86-64大整数表示?

时间:2012-07-18 18:34:15

标签: math x86-64 biginteger arbitrary-precision

x86-64上的高性能原生大整数库如何代表内存中的一个大整数? (或者它有变化吗?有最常见的方式吗?)

天真地,我正在考虑将它们存储为基数2 64 中以0结尾的数字串。

例如,假设X在内存中为:

[8 bytes] Dn
.
.
[8 bytes] D2
[8 bytes] D1
[8 bytes] D0
[8 bytes] 0

设B = 2 64

然后

  

X = D n * B n + ... + D 2 * B 2 + D 1 * B 1 + D 0

空字符串(即8个零字节)表示零。

这是一种合理的方式吗?这种方式的优点和缺点是什么?还有更好的方法吗?

你会如何处理签名? 2的补码是否适用于此可变长度值?

(发现这个:http://gmplib.org/manual/Integer-Internals.html什么是肢体?)

2 个答案:

答案 0 :(得分:2)

我认为它是最高的数组最低值。我在汇编程序中实现了任意大小的数字的添加。 CPU提供carry flag,允许您轻松执行这些操作。您编写了一个以字节大小块执行操作的循环。进位标志包含在下一个操作中,使用“Add with carry”指令(ADC操作码)。

答案 1 :(得分:0)

这里我有一些处理Big Integers的例子。

<强>加成

原则很简单。对于任何更大的溢出,您需要使用CF(进位标志)。让我们考虑两个128位数的加法。

num1_lo: dq 1<<63
num1_hi: dq 1<<63
num2_lo: dq 1<<63
num2_hi: dq 1<<62
;Result of addition should be 0xC0000000 0x000000001 0x00000000 0x00000000
mov eax, dword [num1_lo]
mov ebx, dword [num1_lo+4]
mov ecx, dword [num1_hi]
mov edx, dword [num1_hi+4]

add eax, dword [num2_lo]
adc ebx, dword [num2_lo+4]
adc ecx, dword [num2_hi]
adc edx, dword [num2_hi+4]
jc .overflow

<强>减法

非常类似于添加,尽管您CF现在称为借用。

mov eax, dword [num1_lo]
mov ebx, dword [num1_lo+4]
mov ecx, dword [num1_hi]
mov edx, dword [num1_hi+4]

sub eax, dword [num2_lo]
sbb ebx, dword [num2_lo+4]
sbb ecx, dword [num2_hi]
sbb edx, dword [num2_hi+4]
jb .overflow    ;or jc

<强>乘法

要困难得多。您需要将fisrt数的每个部分乘以第二个数字的每个部分并添加结果。您不必仅增加两个肯定会溢出的最高部分。伪代码:

long long int /*128-bit*/ result = 0;
long long int n1 = ;
long long int n2 = ;
#define PART_WIDTH 32 //to be able to manipulate with numbers in 32-bit registers

int i_1 = 0; /*iteration index*/
for(each n-bit wide part of first number : n1_part) {
    int i_2 = 0;
    for(each n-bit wide part of second number : n2_part) {
        result += (n1_part << (i_1*PART_WIDTH))*(n2_part << (i_2*PART_WIDTH));
        i_2++;
    }
    i++;
}

<强>司

更复杂。用户Brendan在OsDev.org论坛posted示例伪代码,用于划分n位整数。我在这里粘贴它是因为原理是一样的。

result = 0;
count = 0;
remainder = numerator;

while(highest_bit_of_divisor_not_set) {
    divisor = divisor << 1;
    count++;
}
while(remainder != 0) {
    if(remainder >= divisor) {
        remainder = remainder - divisor;
        result = result | (1 << count);
    }
    if(count == 0) {
        break;
    }
    divisor = divisor >> 1;
    count--;
}