如果和和两个加数的按位异或均为负,这意味着什么?
What does it mean if the bitwise XOR of the sum and two addends are both negative?
比如有3个long类型的变量,我们加上a
和b
得到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);
}
我不明白这怎么可能。
如果 (s^a) < 0
,则 s
或 a
的符号位必须为 1,因此 s
或 a
(但不是两者) 必须为负。 s
和 b
相同。所以要么 s
是负数而 a
和 b
都是正数,要么 s
是正数而 a
和 b
都是负数。这两种情况似乎都不可能。
当然,除非你计算整数 overflow/underflow。
这段代码是错误的。
假设有符号整数按位异或的通常 2 的补码规则,则
(s^a) < 0
如果 s
和 a
将它们的符号位设置为相反的值,则 就是这种情况。因此,
((s^a) < 0 && (s^b) < 0)
表示 s
与 a
和 b
的符号不同,因此必须具有等号(假装 0 是正数)。如果你把两个等号的整数相加得到的结果是不同的符号,那肯定是溢出了,所以这就是溢出检查。
如果我们假设有符号溢出回绕,那么 s
与 a
和 b
正好在溢出发生时具有相反的符号。但是,有符号溢出是未定义的行为。计算 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)
它应该转换为 unsigned 以获得定义的溢出行为。由于 Python 错误跟踪器上的 issue 7406,在 5 个不同的地方引入了 cast-to-unsigned 修复,但看起来他们遗漏了一个地方,或者 INPLACE_ADD
可能被更改了自那时候起。我在追踪器上留言了
比如有3个long类型的变量,我们加上a
和b
得到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);
}
我不明白这怎么可能。
如果 (s^a) < 0
,则 s
或 a
的符号位必须为 1,因此 s
或 a
(但不是两者) 必须为负。 s
和 b
相同。所以要么 s
是负数而 a
和 b
都是正数,要么 s
是正数而 a
和 b
都是负数。这两种情况似乎都不可能。
当然,除非你计算整数 overflow/underflow。
这段代码是错误的。
假设有符号整数按位异或的通常 2 的补码规则,则
(s^a) < 0
如果 s
和 a
将它们的符号位设置为相反的值,则 就是这种情况。因此,
((s^a) < 0 && (s^b) < 0)
表示 s
与 a
和 b
的符号不同,因此必须具有等号(假装 0 是正数)。如果你把两个等号的整数相加得到的结果是不同的符号,那肯定是溢出了,所以这就是溢出检查。
如果我们假设有符号溢出回绕,那么 s
与 a
和 b
正好在溢出发生时具有相反的符号。但是,有符号溢出是未定义的行为。计算 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)
它应该转换为 unsigned 以获得定义的溢出行为。由于 Python 错误跟踪器上的 issue 7406,在 5 个不同的地方引入了 cast-to-unsigned 修复,但看起来他们遗漏了一个地方,或者 INPLACE_ADD
可能被更改了自那时候起。我在追踪器上留言了