位运算,原码、反码、补码一网打尽
十进制、二进制、十六进制、反码、源码、补码、>>>为逻辑移位符,>> 算数移位符,<< 移位符
正数的反码、源码、补码是一样的,负数的补码等于负数的反码+1
机器数:一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。
例如:假设计算机字长为8位,十进制中的数+3 ,转换成二进制就是 0000 0011。如果是-3 ,就是 1000 0011 。这里的 0000 0011 和 1000 0011 就是 机器数。
真值:因为第一位是符号位,所以机器数的形式值就不等于真正的数值。
例如上面的有符号数 1000 0011,其最高位1代表负,其真正的数值是 -3,而不是形式值131(1000 0011 转换成十进制等于131)。
所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001 的真值 = +000 0001 = +1
1000 0001 的真值 = –000 0001 = –1
原码:原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。因为第一位是符号位, 所以8位二进制数的取值范围就是:[1111 1111 , 0111 1111]
即[-127 , 127] (这和我们已知的[-128,127]不一样。假设计算机字长是8位的二进制:
正数:[+1]原 = 0000 0001原
负数:[-1]原 = 1000 0001原
反码:反码的表现方式,正数的反码是他本身,负数的反码在其原码的基础上,符号位不变,其他位按位取反。
例: [+1] 原码=0000 0001 反码= 0000 0001
例:[-1]原码=1000 0001 反码= 0111 1110
补码:补码的表现方式,正数的补码是他本身,负数的补码是在原码的基础上,符号位不变,其他位按位取反,并+1.
例: [+1] 原码=0000 0001 反码= 0000 0001 补码=0000 0001
例:[-1] 原码=1000 0001 反码= 1111 1110 补码=1111 1111
低字长转为高字长,补码左侧补符号位到满足高字长的位数。
例:[+2] 原码 0000 0010 反码=0000 0010 8位补码=0000 0010 16位补码 = 0000 0000 0000 0010
例:[-2] 原码 1000 0010 反码=1111 1101 8位补码=1111 1110 16位补码= 1111 1111 1111 1110
位运算(负数的运算是以补码的方式计算的,如果运算结果首位为1,结果也需要求一次补码):
位运算规则:
Java数值运算过程中都是先将十进制转换为二进制然后再进行运算,再把二进制数据转换为十进制展现给用户。二进制运算规则如下:
1、对于有符号的而言,最高位为符号位,0表示正数,1表示负数
2、正数的原码,反码和补码都一样,三码合一
3、负数的反码:符号位保持不限,其他位取反
4、负数的补码:反码 + 1
5、0的反码和补码都是0
6、计算机的运算的时候,都是将原码转成补码进行运算的
7、我们看运算结果要看原码。
与运算(&):两个数相同位置的比特位进行与运算,若两个比特位均为1,则结果就为1,否则为0。
例:5 & 7 = 0000 0101 & 0000 0111 = 0000 0101 = 5
例:5 & -7 = 0000 0101 & 1000 0111的补码(1111 1001)= 0000 0001 反码 = 0000 0001 原码 = 1
或运算(|):两个数相同位置的比特位进行与运算,若两个比特位均为0,则结果就为0,否则为1。
例:5 | 7 = 0000 0101 | 0000 0111 = 0000 0111 = 7
例:5 | -7 = 0000 0101 | 1000 0111的补码(1111 1001)= 1111 1101(运算结果) = 1111 1100 (运算结果的反码)= 1000 0011 (运算结果原码) = -3
异或运算(^):两个数相同位置的比特位进行与运算,若两个比特位相同,则为0,若不相同,则为1。
例:5 ^ 7 = 0000 0101 ^ 0000 0111 = 0000 0010 = 2
例:5 ^ -7 = 0000 0101 ^ 1000 0111的补码(1111 1001)= 1111 1100(运算结果) = 1111 1011 (运算结果反码)= 1000 0100(运算结果原码) = -4
取反运算(~):将数的比特位取反。
例:~5 = 0000 0101 (补码) = 1111 1010 (运算结果)= 1111 1001 (运算结果反码) = 1000 0110 (运算结果原码) = -6
左移运算(<<):将一个数表示的二进制向左移n位,符号位和其他位一样要移动,移出的部分将被抛弃,右侧低位补0,符号位可能会发生变化(因为符号位被会移出抛弃,新的符号位由右侧的左移替上)。
例:15 << 3 = 0000 1111 << 3 = 0111 1000(运算结果) = 0111 1000(运算结果原码正数三码合一) = 8 + 16 +32 + 64 = 120
例:15 << 30 = 0000 0000 0000 0000 0000 0000 0000 1111 << 30 = 1100 0000 0000 0000 0000 0000 0000 0000(运算结果) = 1011 1111 1111 1111 1111 1111 1111 1111(运算结果反码)=1100 0000 0000 0000 0000 0000 0000 0000(运算结果原码)= -2的30次方
例:-15 << 3 = 1000 1111(原码) << 3 = 1111 0001(补码) << 3 = 111 1000 1000(运算结果) = 111 1000 0111(运算结果反码)= 100 0111 1000(运算结果原码)= -(8+16+32+64)= -120
右移运算(>>):将一个数表示的二进制向右移n位,移出的部分将被抛弃,左侧高位补符号位。例如正数左侧补0,负数左侧补1。
例:15 >> 1 = 0000 1111 >> 1 = 0000 0111 = 7
例:-15 >> 1 = 1000 1111(原码) >> 1 = 1111 0001(补码) >> 1 = 1111 1000(运算结果) = 1111 0111(运算结果反码) =1000 1000(运算结果原码)= -8
无符号右移运算(>>>):将一个数表示的二进制无符号向右移n位,移出的部分将被抛弃,无论是正数,还是负数,左侧高位都补0。
例:15 >>> 1 = 0000 1111 >>> 1 = 0000 0111 = 7
例:-15 >>> 1 = 1000 0000 0000 0000 0000 0000 0000 1111 >>> 1 = 1111 1111 1111 1111 1111 1111 1111 0001(补码) >>> 1 = 0111 1111 1111 1111 1111 1111 1111 1000 = 2147483640