java:int的移位距离限制为31位

知道为什么java中int的移位距离限制为31位(右手操作数的低5位)?

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19

x >>> n 

我可以看到一个类似的问题java Bit操作>>>转移但没有人指出正确的答案

移位距离限制为31位,因为Java int具有32位。 将int数移动超过32位将产生相同的值(0或0xFFFFFFFF ,具体取决于您使用的初始值和移位操作)。

这是一个设计决定,但至少对某些用例来说似乎有点不幸。 首先是一些术语:让我们将定义为零的方法称为所有移位量大于移位字中的位数饱和方法,以及Java方法仅使用底部5(或6为long )位来定义移位作为mod方法的数量。

您可以通过列出有用的class次值来查看问题。 这些是产生唯一输出值的移位量1 。 如果你取>>>,有趣的值是0,但包括32。 0导致值不变,32导致0.移位超过32将再次产生与32相同的结果 – 当然 – 但是java甚至不会让你移动32:它在31停止! 如果出乎意料的是,32的变化将使您的价值保持不变。

>>>的许多用途中,不能使用32或者Java行为。 但是,在其他情况下,自然结果是32,并且您必须特殊情况为零。

至于为什么他们会选择那种设计呢? 好吧,它可能有助于当时的普通PC硬件(x86,就像今天一样)以这种方式实现移位(仅使用最后5位用于32位移位,最后6位用于64位)。 因此,移位可以直接映射到硬件而无需任何特殊情况,条件移动或分支2

此外,对于默认情况下不实现这些语义的硬件,通过简单的掩码很容易获得Java语义: shiftAmount & 0x1F 。 在所有硬件上都会很快。 反向映射 – 在不支持它的硬件上实现饱和的转换更复杂:您可能需要昂贵的比较和分支,一些麻烦的黑客或预测的移动来处理> 31情况。

最后,对于许多算法, mod方法是很自然的。 例如,如果要实现一个位图结构,每位可寻址,一个好的实现可能是有一个整数数组,每个整数代表32位。 在内部索引到第N位,你可以将N分成两部分 – 高27位将在数组中找到该字所在的字,而低5位将从该字中选择该位。 要从word选择位(例如,将其移动到LSB),您可以执行以下操作:

 int val = (word >>> (index & 0x1F)) & 1 

如果该位置位,则将val设置为1,否则为0。 但是,由于指定了Java >>>运算符的方式,根本不需要& 0x1F部分,因为它已经隐含在mod定义中了! 所以你可以省略它,事实上JDK的BitSet恰好使用了这个技巧。


1当然,MSB中没有1的任何值都可能不会在>>>下产生唯一值,一旦所有1都被移开,所以让我们只谈一个前导值。

2为了它的价值,我检查了ARM, 语义甚至更奇怪 :对于可变移位,使用移位量的后八位 。 所以换档是一个奇怪的混合 – 一旦你超过31,它实际上是一个饱和的移位,但是只有高达255,此时它会循环并突然在接下来的31个值中具有非零值,等等。