知道为什么java中int的移位距离限制为31位(右手操作数的低5位)?
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19
x >>> n
我可以看到类似的问题java Bit operations >>> shift,但没有人指出正确的答案
答案 0 :(得分:2)
移位距离限制为31位,因为Java int有32位。将int
数字移动超过32位将产生相同的值(0或0xFFFFFFFF
,具体取决于您使用的初始值和移位操作。)
答案 1 :(得分:1)
这是一个设计决定,但至少对某些用例来说似乎有点不幸。首先是一些术语:让我们将定义为零的方法称为所有移位量大于移位字中饱和方法中的位数,以及仅使用Java的方法底部5(或long
)6位用于将移位量定义为 mod 方法。
您可以通过列出有用的班次值来查看问题。这些是移位量,导致唯一的输出值 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和semantics are even weirder:对于变量移位,使用了移位量的底部 8位。所以换档是一个奇怪的混合 - 一旦你超过31,它实际上是一个饱和的移位,但只有高达255,此时它循环并突然有接下来的31个值的非零值等等。