如果和和两个加数的按位XOR都是负数,这意味着什么?

时间:2015-06-25 02:33:12

标签: c binary

例如,有3个长类型变量,我们添加ab并获取s

long a, b, s;
...
s = a + b

现在((s^a) < 0 && (s^b) < 0)是什么意思?

我在Python的source code中看到了这样的支票:

    if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
        /* INLINE: int + int */
        register long a, b, i;
        a = PyInt_AS_LONG(v);
        b = PyInt_AS_LONG(w);
        i = a + b;
        if ((i^a) < 0 && (i^b) < 0)
            goto slow_iadd;
        x = PyInt_FromLong(i);
    }

2 个答案:

答案 0 :(得分:5)

此代码错误。

假设对于有符号整数,通常的2位补码XOR补码规则,那么

(s^a) < 0

sa将其符号位设置为相反值的情况。因此,

((s^a) < 0 && (s^b) < 0)

表示s的标志与ab的标志不同,后者必须具有相同的符号(假装0为正)。如果你添加了两个等号的整数并得到了不同符号的结果,那么一定有溢出,所以这是溢出检查。

如果我们假设已签名的溢出包装,那么sab的符号恰好在溢出发生时相反。但是,签名溢出是未定义的行为。计算s已经错了;我们需要检查是否会在没有实际执行操作的情况下发生溢出。

Python不应该这样做。您可以在Python 2 source code for int.__add__

中查看它应该执行的操作
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)a + b);
if ((x^a) >= 0 || (x^b) >= 0)

它应该转换为无符号以获得定义的溢出行为。由于issue 7406在Python错误跟踪器上引入了5个不同位置的转换为无符号修复,但看起来它们错过了一个位置,或者从那时起可能INPLACE_ADD被更改了。我已经在跟踪器上留言了。

答案 1 :(得分:2)

我不知道这是怎么可能的。

如果(s^a) < 0,则sa的符号位必须为1,因此sa(但不是两者)必须是消极的。 sb也是如此。因此,s为负数,ab均为正数,或s为正数,ab均为正数。这两种情况似乎都不可能。

除非你计算整数溢出/下溢,当然。