二进制中关于负数进行移位运算之后会不会改变符号的探究
移位运算,即:将二进制数向左或向右移动相应位数,为保证数据位数,空缺部分会进行相应的补齐。
毫无疑问,如果该数是正数,那么无论是向左移位或向右移位,
空缺位都应用0补齐,那么对于负数呢?我们知道负数的高位是用1来表示的,那么移位之后会不会以0补齐从而变为正数?
下面进行测试:
右移:
#include <stdio.h>
int main(){
short a = -15;
a = a>>3;
printf("%d\n",a); //结果为-2
return 0;
}
我们来通过二进制码来观察一下:
-15:
原: 0000 0000 0000 1111
反: 1111 1111 1111 0000
补: 1111 1111 1111 0001
右移三位: ???1 1111 1111 1110 1.
此时我们已知结果为-2,所以:
原: 0000 0000 0000 0010
反: 1111 1111 1111 1101
补: 1111 1111 1111 1110 2.
显然,2式就是-15向右移三位之后的结果,说明负数右移之后,空白处全都以1补全,所以负数向右移位之后不会改变符号。
那么负数左移呢?会不会出现最高位变成0的情况呢?我们以同样的方法来观察,代码如下:
(为了使得补码最高位在向左移位之后变为0,我们需要一个大一些的数,或者向左移动更多位数,这里作者选择移动更多位数。)
#include <stdio.h>
int main(){
short a = -9;
a = a<<12;
printf("%d\n",a);
return 0; //结果为28672!!!!惊不惊讶,别慌下结论
}
二进制如下:
-8:
原码: 0000 0000 0000 1001
反码: 1111 1111 1111 0110
补码: 1111 1111 1111 0111
左移12位之后: 0111 0000 0000 0000
好像很有道理的样子,为什么会这样呢?
我们知道,当我们进行向左移位的时候,相当于是乘上2n,n为移动的位数。那么我们将-9*212等于多少呢?-36864,而我们声明的数据类型是short,该数据类型表示的数的范围是-32768-----32767。
显然,我们的结果超出了short类型的范围。
若是将这个数的范围扩大至4byte,那么-9向左移12位之后,结果就会是-36864了。
因此,我们并不能得出,负数向左移位可能会出现变正数的结论。
但是,当我们将数据扩大到4byte之后,将-9向左移动12位之后,显然最高位还是1,并没有变为0。
若我们能证明,对任意一个负整数,向左移动最少位数之后,使得它的补码最高位变为0,此时该数据必然超出当前数据类型的范围,那么我们就可以得出结论:任意一个负整数,向左移动n位之后,仍然在数据类型给定范围内,那么它一定还是负整数。
证明:
要为负整数,那么最高位必然为1,所以当从左起第一个0出现时,0左边一定有至少一个1,而当这个0移动到最高位,前面的1必然超出数据类型范围。
结论:任意一个负整数A,向左移动n位之后得到B,B仍然在数据类型给定范围内,那么B一定还是负整数。
(emmmmm~~虽然篇幅有点长吧,但总算是解释清楚了(个人认为哈),如果有什么地方错误,还请纠正。感谢阅读!)
上一篇: JQuery的Ajax跨域请求的解决方案
下一篇: Js仿php日期格式化方式