简体   繁体   English

二进制算术:为什么hash%n等价于hash&(n-1)?

[英]Binary arithmetic: why hash%n is equivalent to hash&(n-1)?

I have been studying Java HashMap source code, the part of it which decides in what bucket to put an object and saw this change in Java 7 (8) as compared to Java 6. Additionally I conducted numerous experiments and both expressions yeild the same result: 我一直在研究Java HashMap源代码,它的一部分决定了放置一个对象的内容,并在Java 7(8)中看到了与Java 6相比的变化。另外,我进行了大量的实验,两个表达式都有相同的结果:

hash % n
and
hash & (n - 1)
where n - the array length that must be power of 2.

I just cannot figure out why is it true? 我只是想不通为什么是真的? Is there any theorem or some math laws that prove these statement are equal? 是否有任何定理或某些数学定律证明这些陈述是平等的? Basically I want to understand the inference and prove the equivalence of those two statements. 基本上我想理解推论并证明这两个陈述的等价性。

PS. PS。 If n is not a power of 2 number, the equivalence breaks immedeately. 如果n不是2数的幂,则等价性会立即中断。

If n is a power of two that mean its binary representation is 10000.... , 如果n是2的幂,则表示其二进制表示为10000....
n-1 for that matter is 1111111... with one less digit. 对于那个问题,n-1是1111111...少了一个数字。

That means that binary &-ing with (n-1) preserves just exactly the number of bits in k that n-1 has set. 这意味着带有(n-1)二进制&-ing恰好保留了n-1设置的k中的位数。

Example n = 8: 1000, n-1 = 7: 111 实施例n = 8: 1000, n-1 = 7: 111
&-ing for example k = 201: 11001001 &-ing例如k = 201: 11001001
k % n = k & (n-1) = 11001001 & 111 = 001 = 1 . k % n = k & (n-1) = 11001001 & 111 = 001 = 1

%-ing with a power of 2 means that in binary you just strip everything away that is above (including) the only set bit: for n = 8 that means stripping everything over (including) the 4th bit. 使用2的幂的%-ing意味着在二进制中你只需去掉上面(包括)唯一设置位的所有内容:对于n = 8,这意味着剥离所有内容(包括)第4位。 And that is exactly what the &-ing does at well. 而这正是&-ing所做的。


A side effect is that using & is commutative: hash & (n - 1) is equivalent to (n - 1) & hash which is not true for % , the jdk source code in many places uses the later, eg in getNode 副作用是使用&是可交换的: hash & (n - 1)等价于(n - 1) & hash ,对于%不是真的,许多地方的jdk源代码使用后者,例如getNode

Think about the bits in (n - 1) if n is a power of 2 (or ((1 << i) - 1) , if you want to simplify the constraint on n ): 如果n是2的幂(或((1 << i) - 1) ,如果要简化对n的约束,请考虑(n - 1)的位:

If n is, say, 16 ( = 1 << 4) , then n - 1 is 15, and the bit representation of 15 and 16 (as 32-bit int s) are: 如果n是16( = 1 << 4) ,那么n - 11516 (作为32位int )的位表示是:

 1 = 00000000000000000000000000000001  // Shift by 4 to get...
16 = 00000000000000000000000000010000  // Subtract 1 to get...
15 = 00000000000000000000000000001111

So just the lowest 4 bits are set in 15. If you & this with another int, it will only allow bits in the last 4 bits of that number to be set in the result, so the value will only be in the range 0-15, so it's like doing % 16 . 因此,只有最低的4位在15中设置。如果你&另一个int,它只允许在结果中设置该数字的最后4位中的位,因此该值仅在0-范围内15,所以就像在做% 16


However, note that this equivalence doesn't hold for a negative first operand: 但请注意,此等效性不适用于负的第一个操作数:

    System.out.println(-1 % 2);    // -1
    System.out.println(-1 & (2-1));  //  1

Ideone demo Ideone演示

The arithmetic rule for integer / and % is: 整数/%的算术规则是:

x*(y/x) + (y%x) = y

What about a negative hash -4 and a positive n 8? hash -4和正n 8怎么样?

8*0 + (-4%8) = -4

Hence modulo maintains the sign. 因此模数保持符号。

-4 % 8 = -4
-4 & 7 = 4

Or: 要么:

int t = hash%n;
if (t < 0) {
   t += n;
}
assert t == (hash & (n-1));

So in the earlier java with %n hash had to be positive to begin with. 所以在早期的Java中, %n hash必须是积极的开始。 Now hash may be negative, more solid and better hashing. 现在哈希可能是负面的,更稳固和更好的散列。 So that was a sound reason for this subtle change in java source code. 所以这是java源代码中这种微妙变化的合理原因。


Background: 背景:

2 n is a 1 followed by n-1 0 s (in binary). 2 n1,后跟n-1 0 s(二进制)。 2 n - 1 is n-1 1 s. 2 n - 1是n-1 1 s。

Hence for n being a positive power of 2, and some positive number h: 因此,对于n为2的正幂,以及一些正数h:

h % n == h & (n-1)

Another usage is to count bits in an int. 另一种用法是计算int中的位数。 The class Integer has just such a function. Integer类具有这样的功能。

int bits = 0;
while (x != 0) {
    x &= x - 1;
    ++bits;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM