【问题标题】:x86-64 Big Integer Representation?x86-64 大整数表示?
【发布时间】:2012-07-17 21:12:45
【问题描述】:

x86-64 上的高性能原生大整数库如何表示内存中的大整数? (还是会有所不同?有最常见的方法吗?)

我天真地考虑将它们存储为以 0 结尾的以 2 为底的数字字符串64

例如假设X在内存中为:

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

令 B = 264

然后

X = Dn * Bn + ... + D2 * B2 + D 1 * B1 + D0

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

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

您将如何处理签名? 2 的补码是否适用于这个可变长度值?

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

【问题讨论】:

  • 一个“肢体”是字的大小。 (或者更确切地说是基础)它通常是 32 位或 64 位。所以数字以2^322^64 为基数。

标签: math x86-64 biginteger arbitrary-precision


【解决方案1】:

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

【讨论】:

  • 你的 asm bignum 解决方案是开源的吗?
  • 不,抱歉。我25年前在大学写的。添加 bignums 实现起来很简单,并且已经有几个很好的开源库。
【解决方案2】:

这里我有一些处理大整数的例子。

加法

原理很简单。您需要使用CF (carry-flag) 来处理任何更大的溢出。让我们考虑一下两个 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

乘法

要困难得多。您需要将第一个数字的每个部分与第二个数字的每个部分相乘,然后将结果相加。您不必只乘以肯定会溢出的两个最高部分。伪代码:

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++;
}

部门

更复杂。 OsDev.org 论坛上的用户 Brendan 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--;
}

【讨论】:

  • OP 询问的是 x86_64,而不是 x86。而在 x86_64 中,您只需要 2 个寄存器来表示一个 128 位数字。将 rdx:rax 添加到 r11:r10 只需要 2 条指令:add r10, rax; adc r11, rdx
猜你喜欢
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多