通过原码、反码、补码彻底搞清左移、右移、无符号右移

原码、反码、补码

正数
正数的原码、反码、补码都是该数字的二进制表示。
首先我们需要知道,计算机中的移位运算都是以二进制补码形式进行的,就像我们的Integer.toBinaryString(num),其转化出来的数字就是补码的形式。在计算机中是没有正负号的,正数用0表示,负数用1表示。像int,我们知道他是占32位的,但是他的最大数是2^31 - 1,原因就是他有一个是符号位。下面先看几个极限值

System.out.println((1<<31) - 1); //2147483647
System.out.println(1<<31); //-2147483648
int m = -2147483648;
System.out.println(Integer.toBinaryString(m)); //10000000000000000000000000000000

由于int型在日常中比较常用,下面就以int型进行讲解。
这里以55进行举例,为了好理解,我以8位进行讲解

int a = 55;
System.out.println(Integer.toBinaryString(a)); //110111

55的原码是00110111,其中符号位是前面的0,其反码和补码也是00110111。
负数
负数的原码是该数字的二进制表示,反码是符号位不变数值位取反,补码是符号位不变数值位在反码的基础上加1
我们以-83进行讲解,这里也是用8位进行表示,其实前面还有24位1。

int n = -83;
System.out.println(Integer.toBinaryString(n)); //11111111111111111111111110101101

可以看出,输出的是10101101,这里是补码的形式,其中高位的1是符号位。
-83的原码是 11010011,其中第一位的1是符号位,表示是负数。
-83的反码是 10101100,其中第一位的1是符号位,表示是负数。
-83的补码是 10101101,其中第一位的1是符号位,表示是负数。

有符号右移>>

正数
了解了补码之后,移位运算就简单多了,这里的右移,也是有符号右移,其移位运算就是用的补码形式。这里还是用8位的55举例。

int a = 55;
System.out.println(Integer.toBinaryString(a)); //110111
a = a >> 2;
System.out.println(Integer.toBinaryString(a)); //1101
System.out.println(a); //13

55的补码是00110111,右移之后是补码是00001101,原码和反码也是00001101即是13。
负数
负数的有符号右移,这里还用-83进行讲解。

int b = -83;
System.out.println(Integer.toBinaryString(b)); //11111111111111111111111110101101
b = b >> 2;
System.out.println(Integer.toBinaryString(b)); //11111111111111111111111111101011
System.out.println(b); // -21

-83的原码是11010011,反码是10101100,补码是10101101,所以补码右移2位后是11101011
11101011转化为反码是11101010,转化为原码是10010101,即是-21,我们可以看到,移位之后,其位数是不变的,也就是前面的符号位是不变的。

无符号右移>>>

正数
>>>是无符号右移,这里还是以55讲解

int a = 55;
System.out.println(Integer.toBinaryString(a)); //110111
a = a >>> 2;
System.out.println(Integer.toBinaryString(a)); //1101
System.out.println(a); //13

对于正数而言,有符号右移和无符号右移是一样的,因为,有符号右移,移动之后是补了符号位0,而无符号右移也是补了0,着重讲解负数。
负数
负数还是以-83来进行讲解

int b = -83;
System.out.println(Integer.toBinaryString(b)); //11111111111111111111111110101101
b = b >>> 2;
System.out.println(Integer.toBinaryString(b)); //111111111111111111111111101011
System.out.println(b); // 1073741803

看到这个结果是不是很意外,下面来进行细说一下,你就觉得很合理了。
首先-83的原码是11010011,反码是10101100,补码是10101101,这是我们上面以8位进行表示的,很正常,但是在这里就不能简单的用8位来表示了,因为其在无符号右移的时候,前面移出了0,而0取反之后变为了1,所以导致数值变得不敢相信。
这里进行32位详细模拟
-83的原码是 11111111111111111111111111010011
-83的反码(原码数值位取反)是 11111111111111111111111110101100
-83的补码(反码数值位加1)是 11111111111111111111111110101101
无符号右移2位之后补码形式是00111111111111111111111111101011,
正数的反码跟原码一样是00111111111111111111111111101011,
正数的补码和原码也一样00111111111111111111111111101011

int x = 0b00111111111111111111111111101011;
System.out.println(x); //1073741803

经过检验,果然是1073741803

有符号左移<<

对于左移的话就比较简单了,因为他不牵扯到符号的问题,符号位不变就行了,由于这个原因,所以就没有<<<符号了。
这里还是以55和-83进行讲解

int c = 55;
System.out.println(Integer.toBinaryString(c)); //110111
c = c << 2;
System.out.println(Integer.toBinaryString(c)); //110111100
System.out.println(c); //220

可以看出,左边的符号位没有动,只是在左移2位的时候后面添加了两个0而已

int d = -83;
System.out.println(Integer.toBinaryString(d)); //11111111111111111111111110101101
d = d << 2;
System.out.println(Integer.toBinaryString(d)); //11111111111111111111111010110100
System.out.println(d); // -332

也是符号位不变,在左移2位的时候,后面添加了两个0

总结有无符号

有符号:左移1位,相当于乘2,右移动一位相当于除以2
无符号:那真得好好推推了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贺志营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值