最近在《深入理解计算机系统》上看到一道题,分享一下:
假设我们在对有符号值使用补码运算的32位机器人运行代码。对于有符号值使用的是算术右移,而对于无符号值使用的是逻辑右移。变量的声明和初始化如下:
int x = foo(); //任意值
int y = bar(); //任意值
unsigned ux = x;
unsigned uy = y;
对于下面每个C表达式,1)证明对于所有的x和y值,它都为真(等于1);或者2)给出使得它为假(等于0)的x和y的值:
(x > 0) || (x-1 < 0)
假。设x等于Tmin32(32位有符号补码的最小值:-2147483648);那么,x-1必定负溢出等于Tmax32(32位有符号补码的最大值,2147483647),此时表达式等于0。
(x & 7) != 7 || (x << 29 < 0)
真。如果表达式(x&7)!=7的值为0,则x低3位为二进制为111。在32位机器上,左移29位时,此时最高位符号位正好为1必定小于0。
(x*x) >= 0
有符号补码乘法是先将补码按照无符号数相乘,再截断后,将无符号数转成补码得到乘积。所以只要乘积截断之后最高位为1就不成立。比如,当x为65535(0xffff)时,x*x为-131071(0xfffe0001)
x<0 || -x <= 0
真。如果x大于等于0,则-x小于等于0。因为32位补码的表示范围为-2147483648~2147483647。每一个正数都有对应的负数。
x > 0|| -x >= 0
假。如果x小于等于0,设x为Tmin32(32位有符号补码的最小值:-2147483648)。Tmin32的负数等于其本身,没有正数与之对应。
x+y == uy + ux
真。补码和无符号加法有相同的位级行为。x,y转为ux,uy只是数值变化,二进制位并无变化。另外,x+y虽然会有正溢出或负溢出,uy+yu也有正溢出,但是他们在二进制位上都是一样的。进行比较之前,会将有符号补码x和y的结果转换成无符号数。所以比较结果为1。
x*~y + uy * ux == -x
真。利用C语言按位取反的特性,~y=-y-1。代入表达式有x*-y-x+uy*ux。又因为x*y等于ux*uy,所以表达式只剩余-x。