Java左移、右移和无符号右移笔记

通过其它文章学习了Java左移和右移方面的知识,现在将几个博主写的文章和自己的构思进行整合起来,方便学习起来方便些。

一、原码、反码和补码

在开始java位运算的知识之前,我们先来了解几个基础的概念,原码,反码,补码。

1、原码

原码是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1,其余位表示数值的大小。

数值十进制5

[+5]=[00000101](原码)

[ -  5]=[10000101](原码)

2、反码

反码是数值存储的一种,但是由于补码更能有效表现数字在计算机中的形式,所以多数计算机一般都不采用反码表示数,反码的表示方法如下:

  • 正数的反码是其本身

  • 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

[+5]=[00000101](原码)= [00000101](反码)

[ -  5]=[10000101](原码)= [11111010](反码)

3、补码

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。补码的表示方法是:

正数的补码就是其本身

负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

[+5]=[00000101](原码)= [00000101](反码)=[00000101](补码)

[ -  5]=[10000101](原码)= [11111010](反码)=[11111011](补码)

例如-5的反码为11111010,最后一位是0,通过在最后一位加1后,得到的补码为11111011。

如果遇到最后一位是1而不是0呢?

例如[-12] =[10001100](原码)= [11110011](反码)=[11110100](补码)

-12的反码11110011最后一位是1,加1后很容易发现二进制没有2这个数,只有0 、1 。二进制逢二进一就是当任何计算结果等于2的时候就要向前一位进1(完全从十进制类推)。进位的1加到相邻的高位上,相加的低位归零。

也就是1+1等于2后,最后一位归0,向前进一位(从右边向左边数起第二个数),向前进一位后发现也是1,继续归0,继续向前一位,此时数为0,0+1等于1,不等于2了,也就不用向前进位了。

最后的补码就是:11110100

[反码] 11110011

[补码] 11110100

小结

计算机中的符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。而在计算机系统中,数值一律用补码来表示和存储。

二、左移和右移

<<(左移),>>(右移)皆属于位运算符.其运算比乘除快,所以我们可以用其优化代码。

注:大家都知道在Java中int型占4个字节32位,以下数据类型使用int整型32位。

1、左移

<<表示左移,不分正负数,低位补0;
规则则是带符号位移,高位移出,低位补0,移动位数超过该类型的最大位数,则进行取模,如对Integer型左移34位,实际上只移动了两位。无溢出的前提下(左移未超出31位)左移一位相当于乘以2的一次方,左移n位相当于乘以2的n次方。

左移时不管正负,低位补0

示例一:正数20

20<<2;

20的32位二进制原码:00000000  00000000  00000000  00010100   (正数,最高位即第一位数符号位是0)

20的32位二进制反码:00000000  00000000  00000000  00010100 (正数的反码是其本身)

20的32位二进制补码:00000000  00000000  00000000  00010100 (正数的补码就是其本身)

正数的原码=反码=补码,一样的。

向左移动两位后的补码是:00 | 000000  00000000  00000000  00010100 00  

| 前面被剔除两位(从左边开始剔除),右边后面缺少的两个补0(粗体0为补充的两个0)

左移两位后的补码为:00000000  00000000  00000000  01010000

高位符号位是0,说明结果是正数。由于正数的补码跟原码是一样的(补码=原码),这里就不用将补码转成原码,直接拿

00000000  00000000  00000000  01010000计算得到结果。

结果是80。


示例二:负数-20

-20<<2;

-20的32位二进制原码:10000000  00000000  00000000  00010100     (负数,最高位即第一位数符号位是1)

-20的32位二进制反码:11111111  11111111  11111111  11101011   (负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.)

-20的32位二进制补码:11111111  11111111  11111111  11101100   (负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1,遇到+1后的结果等于2时就逢二进一))

向左移动两位后的补码是:11 | 111111  11111111  11111111  11101100 00

| 前面被剔除两位(从左边开始剔除),右边后面缺少的两个补0(粗体0为补充的两个0)

左移两位后的补码为:11111111  11111111  11111111  10110000

负数的补码跟原码不一样,高位符号位是1,说明结果是负数。需要将补码转成原码。这里要计算结果前就需要将补码转换成原码了(补码转原码:符号位不变,数值位按位取反,末位再加1.即补码的补码等于原码)

转成原码后:10000000 00000000 00000000 01010000           

结果是-80。


示例三:正数5

5<<29;

5的32位二进制原码:00000000  00000000  00000000  00000101   (正数,最高位即第一位数符号位是0)

5的32位二进制反码:00000000  00000000  00000000  00000101 (正数的反码是其本身)

5的32位二进制补码:00000000  00000000  00000000  00000101 (正数的补码就是其本身)

正数的原码=反码=补码,一样的。

向左移动29位后的补码是:00000000  00000000  00000000  00000 | 101 00000000000000000000000000000

| 前面被剔除29位(从左边开始剔除),右边后面缺少的补29个0(粗体0为补充的29个0)

左移29位后的补码为:10100000  00000000  00000000  00000000

正数5经过左移29位后的补码高位符号位是1,说明结果是负数。需要将补码转成原码。这里要计算结果前就需要将补码转换成原码了(补码转原码:符号位不变,数值位按位取反,末位再加1.即补码的补码等于原码)

转成原码后:11100000  00000000  00000000  00000000           

结果是-1610612736。


示例四:正数2(超过31的都要继续取模)

2<<32;  结果等于2。因为32取模32后结果等于0,等于没有移位,所以结果等于它本身。

2<<33; 结果等于4。因为33取模32后结果等于1,只移动一位。

这里取模使用建议使用Math.floorMod(33, 32);因为取模与取余有区别的。


2、右移

>>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;右移一位相当于除以2的一次方,右移n位相当于除以2的n次方,原来是正数的还是正数,负数还是负数。

示例一:正数20

20>>2;

20的32位二进制原码:00000000  00000000  00000000  00010100   (正数,最高位即第一位数符号位是0)

20的32位二进制反码:00000000  00000000  00000000  00010100 (正数的反码是其本身)

20的32位二进制补码:00000000  00000000  00000000  00010100 (正数的补码就是其本身)

正数的原码=反码=补码,一样的。

向右移动两位后的补码是:00 00000000  00000000  00000000  000101 | 00

| 后面被剔除两位(从右边开始剔除),前面(左边)缺少的两个补0,即正数高位补0(粗体0为补充的两个0)。

右移两位后的补码为:00000000  00000000  00000000  00000101

高位符号位是0,说明结果是正数。由于正数的补码跟原码是一样的(补码=原码),这里就不用将补码转成原码,直接拿

00000000  00000000  00000000  00000101算得到结果。

结果是5。


示例二:负数-20

-20>>2;

-20的32位二进制原码:10000000  00000000  00000000  00010100     (负数,最高位即第一位数符号位是1)

-20的32位二进制反码:11111111  11111111  11111111  11101011   (负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.)

-20的32位二进制补码:11111111  11111111  11111111  11101100   (负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1,遇到+1后的结果等于2时就逢二进一))

向右移动两位后的补码是:11 11111111  11111111  11111111  111011 | 00

| 后面被剔除两位(从右边开始剔除),前面(左边)缺少的两个补1,即负数高位补1(粗体1为补充的两个1)。

右移两位后的补码为:11111111  11111111  11111111  11111011

负数的补码跟原码不一样,高位符号位是1,说明结果是负数。需要将补码转成原码。这里要计算结果前就需要将补码转换成原码了(补码转原码:符号位不变,数值位按位取反,末位再加1.即补码的补码等于原码)

转成原码后:10000000  00000000  00000000  00000101           

结果是-5。


3、无符号右移

>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0

示例一:正数20

20>>>2;

结果跟20>>2一样。


示例二:负数-20

-20>>>2;

-20的32位二进制原码:10000000  00000000  00000000  00010100     (负数,最高位即第一位数符号位是1)

-20的32位二进制反码:11111111  11111111  11111111  11101011   (负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.)

-20的32位二进制补码:11111111  11111111  11111111  11101100   (负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1,遇到+1后的结果等于2时就逢二进一))

向右移动两位后的补码是:00 11111111  11111111  11111111  111011 | 00  

| 后面被剔除两位(从右边开始剔除),前面(左边)缺少的两个补0。这里需要注意:右移后高位同样补0,而不是1。

右移两位后的补码为:00111111  11111111  11111111  11111011

高位符号位是0,说明结果是正数。由于正数的补码跟原码是一样的(补码=原码),这里就不用将补码转成原码,直接拿

00111111  11111111  11111111  11111011算得到结果。

结果是1073741819。

小结

左移或者右移移位后的补码如果符号位为1的,需要将补码转成原码(符号位为0的表示结果是正数,正数的补码和原码是一样的,不需要转换,可直接计算结果),才能计算得到结果。可使用例如下面代码传入一个正数的32位二进制字符串

/**
 * 传入原码,2表示传入的二进制
 */
System.out.println(Integer.parseInt("00000000000000000000000000000101",2));

得到结果。如果是是负数的,例如负数-5的原码:10000000000000000000000000000101,可以将符号位1改成0,计算得到结果再转成负数。另外无符号右移该数无论是正数还是负数,它的结果都会为正数。如果要计算一个数值的二进制可以使用

/**
 * 返回的是补码二进制,正数12返回1100(可以自行在高位补充0,让其够32位),
 * 负数-12返回11111111111111111111111111110100		
 */
System.out.println(Integer.toBinaryString(12));

参考

我们应该知道的java位运算_zejian_的博客-CSDN博客

Java中的左移、右移详细分析_The best are water的博客-CSDN博客_byte左移8位

一篇文章弄懂左移、右移位运算(Java)_DFYoung的博客-CSDN博客_右移32位相当于

计算机二进制逢二进一怎么算?那句话怎么说的?1+1是不是逢二进一等于向左进一位个位归零是不是这意思_百度知道

原码、反码、补码之间的相互转换_今晚不打老虎的博客-CSDN博客

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值