前言:
今天在看Collections集合类源码中的二分查找的时候,看到了“>>>”符合,并结合“>>”,想做些总结,顺便复习下原码、反码、补码与负数的二进制表示等相关知识。
概念:
“>>>”:无符号右移(不区分正负数,高位补0)
“>>” :带符号右移(正数高位补0,负数高位补1)
带符号左移的概念也就清楚了,值得注意的是,没有无符号左移运算符“<<<”!
原码:
正数:正数的原码就是其绝对值的二进制表示
负数:负数的原码就是其绝对值的二进制表示,然后高位补1
例如:-1 的原码是 10000000 00000000 00000000 00000001
-2 的原码是 10000000 00000000 00000000 00000010
反码:
正数:正数的反码与原码相同
负数:负数的反码等于其原码除符号位以外的各位按位取反
例如:-1 的反码是 11111111 11111111 11111111 11111110
-2 的反码是 11111111 11111111 11111111 11111101
补码:
正数:正数的补码与原码相同
负数:负数的补码等于其反码的最低位加1
例如:-1 的补码是 11111111 11111111 11111111 11111111
-2 的补码是 11111111 11111111 11111111 11111110
注意:二进制计算机中的数字表示用的均是补码
为什么需要补码?
在这里,我们用几个简单的计算来说明:
由于正数的原码、反码、补码都是一样的,下面我们只讨论负数的计算,比如我们要计算:1-1
原码计算:
1 - 1
= 00000000 00000000 00000000 00000001 + 10000000 00000000 00000000 00000001
= 10000000 00000000 00000000 00000010 = -3(10),有问题!
反码计算:
1 - 1
= 00000000 00000000 00000000 00000001 + 11111111 11111111 11111111 11111110
= 11111111 11111111 11111111 11111111
= 10000000 0000000 0000000 0000000(其原码)= - 0(10),有问题!问题在如何区分+0和-0上,因为在人的计算概念中,0是没有正负之分的。
补码计算:
1 - 1
= 00000000 00000000 00000000 00000001 + 11111111 11111111 11111111 11111111
= 00000000 00000000 00000000 00000000 = 0(10),正确!
是不是很神奇!
理解了以上的概念和运算后,我们就可以理解位移运算符了
我们还是以例子来说明,比如说我们用5和-5做说明:
“>>”:
5>>1 = 00000000 00000000 00000000 00000101 >> 1
= 00000000 00000000 00000000 00000010
= 2(10)
-5>>1 = 100000000 00000000 00000000 000000101(原码)>>1
= 11111111 11111111 11111111 11111010(反码)>>1
= 11111111 11111111 11111111 11111011(补码)>>1
= 11111111 11111111 11111111 11111101(补码结果)
= -3(10)
同样的
-4>>1 = 10000000 00000000 00000000 00000100 >>1
= 11111111 11111111 11111111 11111011 >>1
= 11111111 11111111 11111111 11111100>>1
= 11111111 11111111 11111111 11111110
= -2(10)
有的人可能会对“补码求10进制数”的过程有些疑惑,
比如对= 11111111 11111111 11111111 11111101(补码结果)
= -3(10)——为什么是-3?
其实我们倒回去运算,将其转化为原码就好了(对补码再求一次补码)
11111111 11111111 11111111 11111101(补码)
= 10000000 00000000 00000000 00000010(反码)
= 10000000 00000000 00000000 00000011(补码的补码,即原码)
= -3(10)
又或者换另外一种说法,就是已知一个十进制数的补码x,如何求这个十进制数y呢?(由于正数的补码与原码一致,这里的讨论均是讨论该十进制数为负数的情况)
有个公式大家可以参考下:
y = -(!x + 1)
其实也就是求补码的数学表示,可以解释如下:
十进制负数 = 该十进制负数的二进制数按位取反后加1的相反数(有点绕口...)
不过,对于计算来说还是很好用的!
对于无符号右移(“>>>”),其运算规则跟“>>”一致,但是高位需补0!
比如:
-4>>>1
= 10000000 00000000 00000000 00000100 >>1
= 11111111 11111111 11111111 11111011 >>1
= 11111111 11111111 11111111 11111100 >>1
= 01111111 11111111 11111111 11111110
= 2147483646
验证一番: