你的同事对你补码加法溢出条件的分析有些不耐烦了,他给出了一个函数tadd_ok的实现,如下:
//determin whether arguments can be added without overflow
//WARNING: THIS code is buggy
int tadd_ok(int x, int y) {
int sum = x+y;
return (sum-x == y)&& (sum-y == x); }
你看了代码以后笑了,为什么?
错误原因
这个代码看似可以用来检测int型变量的溢出(如果是两个都是负数,那么可能会负溢出,否则可能正溢出),实际上就算溢出了,这个函数也会返回1。因为这个函数想要的是,如果发生溢出,就返回0。
所以你会笑==
推导
原理:sum-x与y是恒相等的。
添加假设:int型内部是4位二进制。即int型的表示范围为
−
2
w
−
1
−
2
w
−
1
−
1
-2^{w-1} - 2^{w-1}-1
−2w−1−2w−1−1。w为4。
补码形式的各个二进制的权值如下:
第4位 | 第3位 | 第2位 | 第1位 |
---|---|---|---|
− 2 3 -2^3 −23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 |
推导:
1)如果没有溢出,那么显然sum-x与y相等。
2)如果发生正溢出,那么最终的值sum为x+y-16。因为正溢出时,两个正数相加入侵到了符号位,本来希望符号位代表 + 2 3 +2^3 +23的值,但是由于这个1在符号位,所以代表的是 − 2 3 -2^3 −23的值。这一来二去,这就比应该的值少了两个 2 3 2^3 23即16。所以就有了sum=x+y-16。但由于16是4位bit int类型的同余数,加减任何整数倍的16都会被截断,都相当于没有加减,所以:
- sum=x+y-16
- sum=x+y
3)如果发生负溢出,推导过程类似。
PS:感谢评论区热心网友的指出。