在C / C ++中没有溢出环绕的二进制加法

时间:2012-02-28 03:00:47

标签: c++ bit-manipulation

我知道当C / C ++发生溢出时,正常的行为是环绕。例如,INT_MAX+1是溢出的。

是否可以修改此行为,因此二进制添加是作为正常添加进行的,并且在添加操作结束时没有回绕?

一些代码,所以这是有道理的。基本上,这是一位(完整)添加,它在32

中逐位添加
int adder(int x, int y)
{
    int sum;
    for (int i = 0; i < 31; i++)
    {
        sum = x ^ y;
        int carry = x & y;
        x = sum;
        y = carry << 1;
    }

    return sum;
}

如果我尝试adder(INT_MAX, 1);它实际上会溢出,即使我没有使用+运算符。

谢谢!

3 个答案:

答案 0 :(得分:4)

溢出意味着添加的结果将超过std::numeric_limits<int>::max()(回到C天,我们使用INT_MAX)。执行此类添加会导致未定义的行为。机器可能崩溃,仍然符合C ++标准。虽然你更有可能得到INT_MIN,但依赖任何结果都没有任何优势。

解决方案是执行减法而不是添加,以阻止溢出并采取特殊情况:

if ( number > std::numeric_limits< int >::max() - 1 ) { // ie number + 1 > max
    // fix things so "normal" math happens, in this case saturation.
} else {
    ++ number;
}

在不知道所需结果的情况下,我无法对其进行更具体的了解。性能影响应该是最小的,因为很少采用的分支通常可以与后续指令同时退役,而不会延迟它们。

修改:要简单地进行数学计算而不必担心溢出或自行处理,请使用bignum库,例如GMP。它非常便携,通常在任何给定平台上都是最好的。它有C和C ++接口。 编写自己的程序集。结果将是不可移植的,次优的,界面将是您的责任!

答案 1 :(得分:2)

不,您必须手动添加它们以检查溢出。

答案 2 :(得分:1)

您希望INT_MAX + 1的结果是什么?您只能将INT_MAX放入int,因此如果您添加一个,结果将更大。 (编辑:在诸如x86 之类的常见平台上,它将包装到最大的负数:-(INT_MAX+1)。获得更大数字的唯一方法是使用更大的变量。

假设int是4字节(在x86编译器上是典型的)并且您正在执行add指令(在32位模式下),目标寄存器只是溢出< / em> - 它没有位,不能容纳更大的值。这是硬件的限制。

要解决此问题,您可以手动编码,或使用执行以下操作的任意大小的整数库:

  • 首先对最低阶词执行正常add指令。如果发生溢出,则设置进位标志。
  • 对于每个越来越高阶的单词,使用adc指令,它会照常添加两个操作数,但会考虑Carry标志的值(值为1。)

您可以看到64位值here