[Java] 移位运算2,你可能不知道的运算

2017-05-09  本文已影响120人  灰灰手记

[Java] 移位运算1
前一篇笔记已经介绍了 Java 移位运算的基本概念和注意事项,接下来将介绍你可能不知道的移位运算。


现象

先看下面的代码:

System.out.println(1 << 31);
System.out.println(1 << 32);
System.out.println(1 << 33);
System.out.println(1 << 34);
System.out.println(1 << 35);

这里的 1 默认是 int 型,32 位。那讲道理左移 31 位就已经满了,再移动就超出了 32 位限制,就应该变为 0 了。但实际结果是这样的:

没有看错,确实没有如我们所想变成 0,反而看起来是对 32 取模之后再以的。
因为不知道上哪去查 Java 移位运算的具体定义,所以多用了几组数据进行测试:

假如我们要对 num 左移 dis 位:
num << dis

  1. 当右操作数 dis >= 0 时,很明显就是先对 dis 取模运算:
    newDis = dis % (num类型长度)
    然后再 num << newDis
  2. 当右操作数 dis < 0 时,就不是先对 dis 取模了,
    因为在 Java 里面 -30 % 32 = -30,运算方法请看 [Java] 取模运算
    这里反而看起来是 newDis = dis + (num类型长度)*n,n 取使 newDis >= 0 的最小值,
    最后再 num << newDis
总结

都换成递归加减法的思想整理一下:
dis >= 0 时,newDis = dis - (num类型长度)*n,n 取使 newDis >= 0 的最大值;
dis < 0 时,newDis = dis + (num类型长度)*n,n 取使 newDis >= 0 的最小值。
但这只是我们通过现象总结出来的结论,没有理论依据,仅供参考。


Java 移位运算定义

最后本人在知乎上提问:Java移位运算超过了会怎样?
感谢知乎大神Kyo Iori的解释,
感谢知乎大神木女孩找来的Java移位运算定义:

Chapter 15. Expressions
If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1**) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1**) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.

这段话简单概括就是:
如果左操作数是 int 型,则取右操作数的低 5 位的值作为移动位数,因为低 5 位的值正好在 0~31 之间;
如果左操作数是 long 型,则取右操作数的低 6 位的值作为移动位数,因为低 6 位的值正好在 0~63 之间。

这时我们再来看前面的例子:


因为这里的 1 默认为 int 型,所以我们先将 33、97、-30、0、35依次转为二进制并取低 5 位值:

 33 = 00000000 00000000 00000000 001 00001 = 00001 = 1
 97 = 00000000 00000000 00000000 011 00001 = 00001 = 1
-30 = 11111111 11111111 11111111 111 00010 = 00010 = 2
  0 = 00000000 00000000 00000000 000 00000 = 00000 = 0
 35 = 00000000 00000000 00000000 001 00011 = 00011 = 3

显然,33、97 的低 5 位都是 00001 = 1,所以
1 << 33 = 1 << 97 = 1 << 1 = 2
而 -30 的低 5 位是 00010 = 2,所以
1 << -30 = 1 << 2 = 4
已经很好理解了,其他就不过多解释了。


[Java] 移位运算1

上一篇下一篇

猜你喜欢

热点阅读