没有进位标志的大整数加法

时间:2012-06-09 09:06:11

标签: c++ c addition arbitrary-precision carryflag

在汇编语言中,通常会有一条指令添加两个操作数和一个进位。如果要实现大整数加法,只需添加最小的整数而不带进位,将下一个整数与进位相加。如何在C或C ++中有效地执行此操作,而我无法访问进位标志?它应该适用于多个编译器和体系结构,所以我不能简单地使用内联汇编等。

4 个答案:

答案 0 :(得分:5)

你可以使用“nail”(来自GMP的术语):在表示数字时,不要使用uint64_t的所有64位,而只使用其中的63位,顶部位为零。这样,您可以通过简单的位移检测溢出。你甚至可能想要少于63个。

或者,你可以做半字算术。如果您可以执行64位算术运算,请将您的数字表示为uint32_t的数组(或者等效地将64位字拆分为上部和下部32位数据块)。然后,当对这些32位整数进行算术运算时,你可以先将64位进行算术运算,然后再转换回来。这可以让你检测进位,如果没有“乘法运算”指令,它也适合乘法运算。

正如另一个答案所示,您可以通过以下方式检测无符号加法中的溢出:

uint64_t sum = a + b;
uint64_t carry = sum < a;

顺便说一句,虽然在实践中这也适用于签名算术,但你有两个问题:

  • 它更复杂
  • 从技术上讲,溢出有符号整数是未定义的行为

所以你最好坚持使用无符号数字。

答案 1 :(得分:3)

你可以凭借这样一个事实弄清楚这一点:如果你通过添加两个数字而溢出,结果总是会小于其他两个数值。

换句话说,如果a + b小于a,则会溢出。这当然是ab的正值,但这几乎肯定是用于bignum库。

不幸的是,一个进位引入了一个额外的复杂功能,即添加最大可能值加上一个进位将为您提供与您开始时相同的值。因此,您必须将其作为一种特殊情况处理。

类似的东西:

carry = 0
for i = 7 to 0:
    if a[i] > b[i]:
        small = b[i], large = a[i]
    else:
        small = a[i], large = b[i]
    if carry is 1 and large is maxvalue:
        c[i] = small
        carry = 1
    else:
        c[i] = large + small + carry
        if c[i] < large:
            carry = 1
        else
            carry = 0

实际上,您可能还想使用数组元素中的所有位来考虑 not

我过去实现了库,其中最大“数字”小于或等于它可以容纳的最高值的平方根。因此,对于8位(八位位组)数字,您存储0到15之间的数值 - 这样,将两位数相乘并添加最大进位将始终与八位位组相匹配,从而使溢出检测没有实际意义,尽管以某些存储为代价。 / p>

类似地,16位数字的范围为0到255,因此它不会在65536处溢出。

事实上,我有时将它限制在更多,确保人工包装值是十的幂(所以一个八位位组将保持0到9,16位数字将是0到99,32位从0到9999的数字,依此类推。

这对空间来说有点浪费,但可以轻松地转换文本(例如打印数字)非常容易

答案 2 :(得分:2)

你可以通过检查检查无符号类型的进位,结果是否小于操作数(任何操作数都可以)。

用carry 0开始。

答案 3 :(得分:0)

如果我理解正确,你想为自己的大整数类型编写自己的附加内容。

您可以使用简单的功能执行此操作。第一次运行时无需担心进位标志。只需从右向左移动,逐位添加进位标志(在该函数内部),从进位0开始,并将结果设置为(a + b +进位)%10并将进位设置为(a + b + carry)/ 10.

这个SO可能是相关的: how to implement big int in c