基础知识
java里存储的都是补码
- 原码转换为反码:符号位不变,数值位分别“按位取反”
- 反码转换为补码:负数为反码末尾末尾+1,正数补码是其本身
计算一个特殊的,比如说-0,原码是1后面31个0,反码则是32个1,在加1就是32个0了(连带着符号位一起进位)。+0的原码是32个0,补码是其本身,自然就是32个0了。
如果要从补码转化为原码,首先看符号位(最高位),如果符号位是0,那么原码就是补码,如果是1,那么-1,然后符号位不变按位取反就行。
左移
左移没有有符号和没符号之分
int i = 1;
System.out.println(i<<1);//2
正数的补码和原码是一样的。int正数的最大值是2^31-1(2147483647)。这是因为第一位是符号为是0。如果将这个数左移,就会发生溢出。下面这个数是0加上31个1,移位完后就是31个1加0。转化为原码,第一步-1,结果为30个1,1个0,一个1,符号为不变取反,结果为符号为1,30个0,一个1,一个0,所以答案是-2。
int i = 2147483647;
System.out.println(i<<1);//-2
总结,左移就是在左边补0,直接对补码操作。
有符号右移
有符号右移的关键是在右边补符号位
int i = 4;
System.out.println(i>>1);//2
int i = -4;
System.out.println(i>>1);//-2
所以,在不溢出的情况下,相当于对原来的数除以2
有一道看似简单的算法题,让求解一个数字中二进制数位中1的数量,显然,如果你错误的使用了有符号右移动而且测试用例还是个负数,就一定做不对了。
无符号右移
int i = -4;
System.out.println(i>>>1); //2147483646