Java的移位运算

前言

计算机支持两种移位运算,假设操作数为x,移动的位数为k,则向左移位是 x << k,向右移位是 x >> k。左移位会对输入的操作数舍弃最高的k位,并在右端补k个0。而右移位运算却分为两种情况,分别是逻辑右移和算术右移(也叫无符号右移和符号右移),在逻辑右移中,会对操作数舍弃最低的k位,并在左端补k个0,在算术运算中,则对操作数舍弃最低的k位,并在左端补k个最高有效位的值。

对于有符号数来说,最高位有效值是不同的,所以逻辑右移和算术右移将产生不同的效果,而C语言并没有明确定义有符号数该使用哪种类型的右移,虽然两种右移都可以,但是现在几乎所有的编译器/机器组合都会对有符号数使用算术右移。而Java比C强大的一个地方在于它对右移有明确的定义,规定 x >> k 使用算术右移, x >>> k 使用逻辑右移。

本文将通过几个实际的例子,并手动计算二进制执行过程,来探究当操作数分别为正数和负数时,Java的移位运算是怎么实现的。

左移位运算

左移运算也相当于做乘法运算,乘积因子为 2^k。例如,我们执行149 << 4,相当于执行了 149*16 = 2384。

1)正数左移位运算

System.out.println (149 << 4);
System.out.println (Integer.toBinaryString ( 149 << 4 ));
2384
100101010000

149 << 4 的计算过程如下:

输入:            149

转为二进制: 10010101

展开32位:       00000000 00000000 00000000 10010101

丢弃最高4位:  0000 00000000 00000000 10010101

右端补4个0: 0000 00000000 00000000 10010101 0000

忽略符号位: 10010101 0000

转为十进制: 2384

可以看出,我们计算过程的最后两步和程序打印效果完全一致。

2)负数左移位运算

System.out.println (-149 << 4);
System.out.println (Integer.toBinaryString ( -149 << 4 ));
-2384
11111111111111111111011010110000

-149 << 4 的计算过程如下:

输入:            -149

转为二进制: 11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

丢弃最高4位:  1111 11111111 11111111 01101011

右端补4个0: 1111 11111111 11111111 01101011 0000

以上是个负数二进制,现要转成十进制,按照以下三步进行:

                       1111 11111111 11111111 01101010 1111      (减1)

                       0000 00000000 00000000 10010101 0000(取反)

                      -10010101 0000                                           (忽略符号位,并添负号)

转为十进制: -2384

可以看出,我们计算过程的第4步和最后一步的计算结果和程序打印效果完全一致。

右移位运算

右移运算也相当于做除法运算,被除数为 2^k。例如,我们执行149 >> 4,相当于执行了 149/16 = 9。

1)正数右移运算

Java的基本类型数据都是有符号数,最高位为1表示负数,最高位为0表示正数。所以对于正数来说,逻辑右移和算术右移没有任何区别,因为都是在左端补0。

System.out.println (149 >> 4);
System.out.println (Integer.toBinaryString ( 149 >> 4 ));
System.out.println (149 >>> 4);
System.out.println (Integer.toBinaryString ( 149 >>> 4 ));
9
1001
9
1001

149 >> 4 计算过程:

输入:            149

转为二进制: 10010101

展开32位:     00000000 00000000 00000000 10010101

丢弃最低4位:00000000 00000000 00000000 1001

左端补4个0:  0000 00000000 00000000 00000000 1001

忽略符号位:  1001

转为十进制:  9

149 >>> 4 的计算过程和上面完全一样,左端都是补4个0,所以打印效果当然是一致的。

2)负数右移运算

当输入的数据是负数,此时逻辑右移和算术右移将产生较大区别。由于负数高位是1,所以逻辑右移和算术右移在左端分别补0和1。

System.out.println (-149 >> 4 );  //负数的算术右移
System.out.println (Integer.toBinaryString ( -149 >> 4 ));
System.out.println (-149 >>> 4 ); //负数的逻辑右移
System.out.println (Integer.toBinaryString ( -149 >>> 4 ));
-10
11111111111111111111111111110110
268435446
1111111111111111111111110110

a)-149 >> 4 计算过程(负数的算术右移):

输入:           -149

转为二进制:   11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

丢弃最低4位: 11111111 11111111 11111111 0110

左端补4个1:1111 11111111 11111111 11111111 0110

相应十进制:  -0000 00000000 00000000 00000000 0101   (ps: 减1,取反,添负号。)

转为十进制:-10

可以看出,我们第4步和第6步运算结果和代码打印的前两行完全一致。

b)-149 >>> 4 计算过程(负数的逻辑右移):

输入:               -149

转为二进制:    11111111 11111111 11111111 01101011       (ps: 绝对值二进制取反再加1。)

丢弃最低4位:  11111111 11111111 11111111 0110

左端补4个0: 0000 11111111 11111111 11111111 0110

转为十进制: 268435446

可以看出,我们第3步和第5步运算结果和代码打印的后两行完全一致。

  • 15
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alphathur

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

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

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

打赏作者

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

抵扣说明:

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

余额充值