首页 > 代码库 > 关于移位的有意思的小问题
关于移位的有意思的小问题
首先,直接上题目:
根据X得到F和G,其中X、F、G均是有符号的32位整型数,其中F = X/2; G = X>>1; 发现 F != G,下面的说法哪个是正确的:
A 编译错误 B X是奇数 C X是负数 D F-G=1
上述4个选项中,首先排除A和B,显然随便举个反例就有了。
对于C,这里就涉及到负数在计算机中的表示形式了,至于怎么个表示法,下面一一道来:
对于负数,在计算机内的表示方法是怎么样的呢?
下面的代码可以说明一切:
void print(int x) { //这里将形参的int转化为unsigned int,是为了说明负数的补码表示方法而已。 unsigned int tmp = x; cout << tmp << endl; string s; while(tmp) { if(tmp & 1) s.push_back('1'); else s.push_back('0'); tmp >>=1; } reverse(s.begin(),s.end()); cout << s << endl; }上述代码的执行结果, x = 9 时,执行结果为:
1111 1111 1111 1111 1111 1111 1111 0111
这里的补码的表示其实很简单,转化过程无非是原码,反码和补码的顺序而已:
原码: 1 000 0000 0000 0000 0000 0000 0000 1001 //最高位是符号位,后面的31位是数字位
反码: 1 111 1111 1111 1111 1111 1111 1111 0110 //除了符号位,其他为全部变反
补码: 1 111 1111 1111 1111 1111 1111 1111 0111 //反码加1即可
这样的话,对于上述的代码的结果解析就这样了,现在执行 :
F = X/2 = -9/2 = -4 ; // 这就是除法运算
G = X>>1 = (-9) >> 1 就是将上述的补码部分向右移一位,执行过称为:
1 111 1111 1111 1111 1111 1111 1111 0111
1 1 111 1111 1111 1111 1111 1111 1111 0111 //去掉最右边的蓝色的1,加上最左边的绿色的1
于是乎,上述结果变为:
1 1 111 1111 1111 1111 1111 1111 1111 011 //这里是结果的补码,现在讲结果的补码转换为源码,从而得到原来的数值。其过程为:
1 111 1111 1111 1111 1111 1111 1111 1011 //补码
1 111 1111 1111 1111 1111 1111 1111 1010 //补码减去1 变为反码
1000 0000 0000 0000 0000 0000 0000 0101 //除了最高位的符号位,其他为变反,
结果竟然是-5!!!! 也就是说 (-9 >> 1) = -5 !!!!
也就是说出现了上述的 F != G, F-G = 1 。于是答案是D.
关于移位的有意思的小问题