我正在阅读以下代码为何出错:
int tadd_ok ( int x, int y ) {
int sum = x + y;
return ( sum - x == y ) && ( sum - y == x );
}
解释是,两个补语加法形成一个阿贝尔群,所以表达式为
无论加法是否溢出,(x + y) - x
评价为y
((x + y) - y)
的评分为x
)。
我不理解这个解释或阿贝尔群体的参考。二进制补码基本上是无符号模运算,它被转换成#34;对于两个补充,对吗?
因此,例如,如果我们有4位,我们有范围[-8,7]。
在示例中,如果我们有x = 7
和y = 6
,则结果溢出为6.而且这不等于y
或x
。
那么,为什么解释说,无论溢出,等式总是有效的?
答案 0 :(得分:3)
“阿贝尔”组只是意味着你添加东西的顺序无关紧要 - (a + b)+ c = a +(b + c)和(a + b)==(b + a)。
这对于C中的整数是正确的。技术上是正确的,因为@ouah指出溢出是未定义的,但这是为了在不使用两个恭维数学的处理器上轻松支持C标准。大多数人都这样做。
关于那些,除非在编译器中发生非常奇怪的事情(或者不那么奇怪,但是优化 - 感谢@ouah),无符号数学将作为一个阿贝尔群。
在您的示例中,7 + 6 = 0111 + 0110 == 1101是 - (0010 + 1)= -3。在两个补码签名系统中,负数“以二进制计数”:1111为-1。减去1010,或0101 + 1 = 6。
答案 1 :(得分:1)
这是个老问题,但希望我的回答对某人有用。
这是因为要修复正溢出(当 x + y > TYPE_MAX
时)我们需要从总和中减去 2^n
并修复负溢出(当 x + y < TYPE_MIN
时)我们需要添加 { {1}}(需要一堆数学语句来说明这一点,所以我决定不将它们包含在答案中)。
因此,如果 2^n
正溢出,x + y
实际上等于 sum
。在此之后,当我们执行比较时,我们从 x + y - 2^n
中减去 x
,这会导致负溢出,因此我们有 sum
实际上等于 sum - x
。因此,sum - x + 2^n
。另一个介词也会发生同样的情况。