Java中的位移操作

问题

想要了解Java内部如何处理位移长度是负数的,如100 << -5的值是多少?问题的来源是JDK的Integer类中有如下两个方法:

1
2
3
4
5
6
7
public static int rotateLeft(int i, int distance) {
    return (i << distance) | (i >>> -distance);
}

public static int rotateRight(int i, int distance) {
    return (i >>> distance) | (i << -distance);
}

有意思的地方在于移位长度使用了负数。它的原理是什么?

讨论

《核心Java》一书说右操作数在执行位移前需要对32取模,显然对于负数的情况不能适用,因为在Java中,负数取模之后依然是负数。《Java编程思想》中认为只有右操作数的低5位参与运算。按照补码的定义,对于任意的整数,x,0<x<32,都满足-x的低5位等于32-x。对于任何不在此范围内的整数都可以通过取模映射进来。

1
2
3
4
out.println(toBinaryString(-5));
out.println(toBinaryString(32-5));
out.println(toBinaryString(-32-5));
out.println(toBinaryString(32+32-5));

代码输出如下:

11111111111111111111111111111011
11011
11111111111111111111111111011011
111011

可以看到它们的低5位都是11011。从而不难看出,i >>> -distance等于i >>> (32-distance%32)i << -distance等于i << (32-distance%32)

参考阅读

《The Java Language Specification, Java SE 8 Edition.》 15.17.3 Remainder Operator % 《Thinking in Java》 Shift operators 《Core Java. Volume I·Fundamentals》 Bitwise Operators