在Java中,使用移位时,为什么1 << 32!= 1 << 31 << 1?


问题内容
int a = 1 << 32;
int b = 1 << 31 << 1;

为什么a == 1呢?b如我所料是0。


问题答案:

所有移位都针对整数进行mod 32,对long进行mod 64。

规范的第15.19节开始

如果左侧操作数的提升类型为int,则仅将右侧操作数的最低5位用作移位距离。就像右侧操作数受到掩码值0x1f的按位逻辑AND运算符&(§15.22.1)一样。因此,实际使用的移动距离始终在0到31(含)范围内。

如果左侧操作数的提升类型为long,则仅将右侧操作数的六个最低位用作移位距离。就像右侧操作数受到掩码值0x3f的按位逻辑AND运算符&(§15.22.1)一样。因此,实际使用的移动距离始终在0到63之间(包括0和63)。

至于 为什么 以这种方式设计语言-我不知道,但是C#拥有相同的设计决策。这是带注释的ECMA C#规范所说的内容:

C#故意将实现定义的行为保持在最低水平。仅当强制执行统一行为对性能的影响过大时(例如,对于某些浮点精度问题),才接受它们。因此,每个整数类型的大小都可以精确指定,并且字符集固定为Unicode。

对于换档操作,也指定了统一的行为。可以使用一条额外的指令(&0x1F或&0x3F)来实现,这条指令在现代处理器上只会产生很小的成本,尤其是因为它不引用内存。与浮点运算不同,如果让处理器心血来潮,则换档行为的差异将非常明显。而不是精度上的微小差异,将产生完全不同的积分结果。

在做出此决定时,委员会研究了许多不同处理器体系结构的参考资料。对于32位操作数,移位计数超出-32 .. + 32范围,对于64位操作数,超出-64
.. + 64范围时,行为几乎没有一致性。

(然后是一些示例的列表。)

对我来说,这似乎是一个完全合理的解释。一致性绝对重要,如果在某些系统上无法以高性能方式实现 不同的 一致行为,我认为这是一个合理的解决方案。