模32或模64的约简是什么?

4
在《Core Java Volume1》一书中有一个警告,它说:

注意:移位运算符的右侧参数对32取模(除非左侧是long类型,此时右侧对64取模)。例如,1 << 35的值与1 << 3或8相同。

这到底是什么意思?为什么1在左移35位后变成了8而不是0?
谢谢。
3个回答

13

模32取余(基本层面上)意味着你不断地减去32,直到得到一个介于0和31之间的数。

换句话说:

actualValue = givenValue % 32;

原因是因为将一个32位的值向左(或向右)移动32位几乎没有意义,因为这将总是得到零(因为你正在一侧移出位并在另一侧移入零 - 对32位值进行这样的操作无论最初的值如何,结果都会是零)。

因此,对于Java中的整数(32位),31是合理的限制。对于长整型(64位),63是合理的限制。

在您提供的示例中,1 << 35将移位值从35减少到3(因为35%32 == 3),而1 << 3是8:

 Binary
0000 0001    (1 << 0) == 1
0000 0010    (1 << 1) == 2
0000 0100    (1 << 2) == 4
0000 1000    (1 << 3) == 8
     ||||
     |||+--- 1
     ||+---- 2
     |+----- 4
     +------ 8

更多信息,请参考语言参考手册:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.19 - dsummersl

6
在许多编程语言中,一个数字数据类型的大小(int是32位,long是64位)之外的移位是未定义的。然而,在Java中,它被定义为(n<<d)等同于(n<<(d%32)),其中n是int类型,(n<<d)等同于(n<<(d%64)),其中n是long类型。
因此,1<<35相当于1<<(35%32),即1<<3=8

4
更简洁地说。
a << b

等同于

a << (b & 31)

对于int类型而言,两者的区别在于 -1 % 32 的结果是 -1,而 -1 & 31 的结果是 31,1 << -1 == 0x80000000

这种行为在JLS 15.19中有定义。

如果左操作数提升后的类型为int,则只使用右操作数的最低5位作为移位距离。就好像右操作数被位逻辑与运算符&(§15.22.1)与掩码值0x1f(0b11111)进行按位与运算一样。实际使用的移位距离因此总是在0到31之间,包括0和31在内。

如果左操作数提升后的类型为long,则只使用右操作数的最低6位作为移位距离。就好像右操作数被位逻辑与运算符&(§15.22.1)与掩码值0x3f(0b111111)进行按位与运算一样。实际使用的移位距离因此总是在0到63之间,包括0和63在内。


@mug896 这在 JLS 中有定义。我更新了我的答案。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接