如何正确添加/减去128位数字(如两个uint64_t)?

时间:2011-01-21 09:45:20

标签: c math int128

我在C中工作,需要添加和减去64位数字和128位数字。结果将保存在128位数字中。我使用整数数组来存储128位数字的上半部分和下半部分(即uint64_t bigNum[2],其中bigNum[0]是最不重要的。)

任何人都可以帮助使用加法和减法函数,该函数可以接受bigNum并为其添加/减去uint64_t吗?

我在网上看到了很多不正确的例子,请考虑一下:

bigNum[0] = 0;  
bigNum[1] = 1;  
subtract(&bigNum, 1);

此时bigNum[0]应设置所有位,而bigNum[1]不应设置位。

5 个答案:

答案 0 :(得分:2)

在1年级或2年级,你应该学会如何将1和10分成几部分,通过将它分成几个单位和单位的多个单独添加。处理大数时,相同的原理可以应用于计算任意大数的算术运算,通过实现你的单位现在是2 ^位的单位,你的“十位”大2 ^位等等。

答案 1 :(得分:1)

这适用于减法:

typedef u_int64_t bigNum[2];

void subtract(bigNum *a, u_int64_t b)
{
  const u_int64_t borrow = b > a[1];

  a[1] -= b;
  a[0] -= borrow;
}

增加非常相似。当然,上述内容也可以通过明确的测试来表达,但我发现总是借用它会更清晰。优化留作练习。

对于等于bigNum的{​​{1}},减去2将使其等于{ 0, 1 },这是表示-1的正确位模式。这里,假设UL将整数提升到64位,当然这取决于编译器。

答案 2 :(得分:0)

对于您减去的值小于或等于bignum[0]的情况,您不必触摸bignum[1]

如果不是,则无论如何都会从bignum[0]中减去它。此操作将环绕,但这是您需要的行为。此外,您必须从bignum[1]中删除1。

答案 3 :(得分:0)

大多数编译器本质上支持__int128类型。

尝试一下,你可能会很幸运。

答案 4 :(得分:0)

在许多架构中,添加/减去任意长整数非常容易,因为有一个进位标志和带有标志指令的add / sub。例如,在x86 rdx:rax += r8:r9上就可以这样做

add rax, r9
adc rdx, r8

在C中,无法访问此进位标志,因此您必须自己计算该标志。最简单的方法是检查无符号和是否小于操作数like this。例如要做a += b,我们会这样做

aL += bL;
aH += bH + (aL < bL);

这是一些example assembly output