[Java] 移位运算2,你可能不知道的运算
[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
- 当右操作数
dis >= 0
时,很明显就是先对 dis 取模运算:
newDis = dis % (num类型长度)
然后再num << newDis
- 当右操作数
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
已经很好理解了,其他就不过多解释了。