Part 1
我们首先需要理解 − x = ∼ x + 1 -x=\sim x+1 −x=∼x+1。众所周知,计算机是通过补码的方式存储整数的(关于补码的知识可以阅读CSAPP)。
我们先来感性认识一下:对于一个整数,例如6=0b0110,~ 6=0b1001,~6+1=0b1010=-6。接下来我们来严格证明一下:
x = − a w ∗ 2 w + ∑ i = 0 w − 1 a i ∗ 2 i − x = a w ∗ 2 w − ∑ i = 0 w − 1 a i ∗ 2 i ∼ x = − ( 1 − a w ) ∗ 2 w + ∑ i = 0 w − 1 ( 1 − a i ) ∗ 2 i ∼ x + 1 = − 2 w + a w ∗ 2 ∗ w + ∑ i = 0 w − 1 2 i − ∑ i = 0 w − 1 a i ∗ 2 i + 1 = − x □ x=-a_w*2^w+\sum_{i=0}^{w-1}a_i*2^i\\-x=a_w*2^w-\sum_{i=0}^{w-1}a_i*2^i\\\sim x=-(1-a_w)*2^w+\sum_{i=0}^{w-1}(1-a_i)*2^i\\\sim x+1=-2^w+a_w*2*w+\sum_{i=0}^{w-1}2^i-\sum_{i=0}^{w-1}a_i*2^i+1=-x\Box x=−aw∗2w+i=0∑w−1ai∗2i−x=aw∗2w−i=0∑w−1ai∗2i∼x=−(1−aw)∗2w+i=0∑w−1(1−ai)∗2i∼x+1=−2w+aw∗2∗w+i=0∑w−12i−i=0∑w−1ai∗2i+1=−x□
Part 2
然后我们去理解 x & ( ∼ x + 1 ) x\&(\sim x+1) x&(∼x+1)就可以得到最低位的1。
在 ∼ x \sim x ∼x后,原本是0的位置都变成了1,原本是1的位置都变成了0,再次+1后,低位原本是0 的位置由于全部变成了1然后都会进位,直到进位到第一个原本是1的位置(此时是0)。也就是说原本最低位的1再次变成了1,而高位全部相反,低位全都是0,所以再次&后就会得到最低位的1。
Part 3
我们都知道,一个字长为w的整数,可以表示的范围是 2 w − 1 ∼ − 2 w 2^w-1\sim -2^w 2w−1∼−2w,对于最小值MIN,我们是无法表示-MIN也就是 2 w 2^w 2w,在实际环境,计算机会进行 ∼ M I N + 1 \sim MIN+1 ∼MIN+1的运算,最终得到MIN本身,也就是说,-MIN=MIN。
int main() {
int x = INT_MIN;
cout << x << endl;
cout << -x << endl;
if (x == -x) {
cout << "same" << endl;
} else {
cout << "different" << endl;
}
return 0;
}
/*运行结果
-2147483648
-2147483648
same
*/
所以MIN&-MIN并不会得到最低位的1,而是会得到0。因此我们在使用x&-x得到x最低位1的时候必须特判x是否为MIN,否则会有潜在的BUG。