Java 负数二进制表示、位运算、移位运算

最近在看 Doug Lea 大神写的并发编程的时候,经常会看到一些正负数的位运算和移位运算,以及一些符号等出现在代码中,不经勾起了对这些知识的回忆…

负数的二进制

计算机中的有符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两
部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同  。在计算机系
统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同
时,加法和减法也可以统一处理。

-x = !x+1 这个等式表示两边的二进制相等,x表示一个正整数,-x表示x的相反数的二进制,!x 表示x的二进制按位取反,然后+1

原码:正数的原码就是他的二进制,负数的原码就是他的绝对值的二进制的最高位补1。
反码:正数的反码与原码相同,负数的反码为他的原码除符号位外全部按位取反。
补码:正数的补码与原码相同,负数的补码为他的原码除符号位外全部按位取反,然后+1。

举例
在java中,一个int占8字节,32bit,下面以32位二进制表示

 1的原码:0000 0000 0000 0000 0000 0000 0000 0001
-1的原码:1000 0000 0000 0000 0000 0000 0000 0001
-1的反码:1111 1111 1111 1111 1111 1111 1111 1110
-1的补码:1111 1111 1111 1111 1111 1111 1111 1111

位运算

在 java 中,经常能看到代码中写到:&、|、~、^ 这几个符号,分别代表按位与、或、非、异或运算

举例

0100 & 1101 = 0100   同一位上都为1则返回1,从左至右,从高到低
0100 | 1101 = 1101   同一位上有一个为1则返回1
0100 ^ 1101 = 1001   同一位上互不相同则返回1

~1 = - 2
验证

0000 0000 0000 0000 0000 0000 0000 0001   // 1的补码
1111 1111 1111 1111 1111 1111 1111 1110  // 1的补码取反
1的补码取反后高位为1,说明是负数,先减1,得到反码: 
1111 1111 1111 1111 1111 1111 1111 1101
再取反,得到原码:1000 0000 0000 0000 0000 0000 0000 0010
其代表10进制数为-2,所以 ~1 = -2

移位运算

左移(<<):按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。例:1 << 2,0001 》0100 = 4

右移(>>):按二进制形式把所有的数字向右移动对应位移位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。右移一位相当于除2,右移n位相当于除以2的n次方。4 >> 2,0100 》 0001 = 1

无符号右移(>>>):按二进制形式把所有的数字向右移动对应位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。其他和右移相似。

-4 >>> 2 = 1073741823
推算过程

0000 0000 0000 0000 0000 0000 0000 0100   // 4的原码
1000 0000 0000 0000 0000 0000 0000 0100  // -4的原码
1111 1111 1111 1111 1111 1111 1111 1011  // -4的反码
1111 1111 1111 1111 1111 1111 1111 1100  // -4的补码
0011 1111 1111 1111 1111 1111 1111 1111  // -4的补码无符号右移2
// 0011 1111 1111 1111 1111 1111 1111 1111 
// 等于 1*2^29 + 1*2^28 + ... + 1*2^0 ,所以初始值设置为 1*2^29 = 1 << 29
public static void main(String[] args) {
    Integer num = 1 << 29;
    Integer total = num;
    for (int i=28; i>=0; i--) {
        num = num >> 1;
        total += num;
    }
    
    System.out.println(total);
    System.out.println(-4 >>> 2);
}

你可能感兴趣的:(Java)