时不时地会被这两个绕一下,干脆写个demo加深记忆。
背景知识
- java 中的整型int占4个字节,也就是32位,首位为符号位,0表示正数,1表示负数。
- 计算机中数值采用补码的方式存放
规律:
- 首位为符号位,0表示正数,1表示负数
- 正整数的原码、反码、补码 三码合一
- 负整数的反码:符号位不变,其余按位取反
- 负整数的补码:反码+1,也就是符号位不变,其余按位取反,然后再加上1
- 补码的补码等于原码
ps: java中可以使用Integer.toBinaryString()来获取一个整数的补码表示,注意这里是补码,不是原码,原码=补码的补码。
有符号右移运算>>
1.将正整数11有符号右移3位:
+11>>
很容易看出:
对于正整数:有符号右移n位,结果的补码等于在高位补了n个0,低位溢出舍弃
正整数原码、反码和补码 三码合一,所以不需要操心太多。
2.将负整数-11有符号右移3位:
-11>>
注意注意,这里的结果是补码哦。
根据补码的补码等于原码规律,可以求出原码是:10000000000000000000000000000010,换算成整数是-2
对于负整数:有符号右移n位,结果的补码等于在补码的高位补了n个1,低位溢出舍弃
注意是结果的补码,不是原码。
无符号右移运算>>
1.将正整数11无符号右移3位:
+11>>>
这里跟有符号右移是一样的。
2.将负整数-11无符号右移3位:
-11>>>
可以看出是在高位补了3个0哈。
对于负整数:无符号右移n位,结果的补码等于在补码的高位补了n个0,低位溢出舍弃
所以无符号右移,对于正整数和负整数,结果的补码都等于是在高位补0.
正整数无符号右移一位等于除以2再向下取整
补充一点,一个正整数,无符号右移一位等于这个整数除以2,再向下取整。
4>>>1,结果为2;5>>>1,结果为2
原理很容易想明白,比如5的二进制是101,右移一位得到010,也就是整数2.
注意,只有正整数可以这样算噢,正整数三码合一,负整数原码补码不一样,不能这样算的噢。
源代码:
/**
* 有符号右移和无符号右移
*/
public class RightShift {
public static void main(String args[]){
RightShift rightShift = new RightShift();
rightShift.signedRightShift(11);
rightShift.signedRightShift(-11);
rightShift.unsignedRightShift(11);
rightShift.unsignedRightShift(-11);
}
/**
* 有符号右移
* @param n
*/
public void signedRightShift(int n){
System.out.println(n+"的有符号右移...........");
System.out.println("参数整型是:"+n);
System.out.println("参数补码是:"+Integer.toBinaryString(n));
int a = n>>3; // 有符号右移三位
System.out.println("结果整型是:"+a);
System.out.println("结果补码是:"+Integer.toBinaryString(a));
}
/**
* 无法符号右移
* @param n
*/
public void unsignedRightShift(int n){
System.out.println(n+"的无符号右移...........");
System.out.println("参数整型是:"+n);
System.out.println("参数补码是:"+Integer.toBinaryString(n));
int a = n>>>3; // 无符号右移三位
System.out.println("结果整型是:"+a);
System.out.println("结果补码是:"+Integer.toBinaryString(a));
}
}