簡體   English   中英

二進制算術:為什么hash%n等價於hash&(n-1)?

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

我一直在研究Java HashMap源代碼,它的一部分決定了放置一個對象的內容,並在Java 7(8)中看到了與Java 6相比的變化。另外,我進行了大量的實驗,兩個表達式都有相同的結果:

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

我只是想不通為什么是真的? 是否有任何定理或某些數學定律證明這些陳述是平等的? 基本上我想理解推論並證明這兩個陳述的等價性。

PS。 如果n不是2數的冪,則等價性會立即中斷。

如果n是2的冪,則表示其二進制表示為10000....
對於那個問題,n-1是1111111...少了一個數字。

這意味着帶有(n-1)二進制&-ing恰好保留了n-1設置的k中的位數。

實施例n = 8: 1000, n-1 = 7: 111
&-ing例如k = 201: 11001001
k % n = k & (n-1) = 11001001 & 111 = 001 = 1

使用2的冪的%-ing意味着在二進制中你只需去掉上面(包括)唯一設置位的所有內容:對於n = 8,這意味着剝離所有內容(包括)第4位。 而這正是&-ing所做的。


副作用是使用&是可交換的: hash & (n - 1)等價於(n - 1) & hash ,對於%不是真的,許多地方的jdk源代碼使用后者,例如getNode

如果n是2的冪(或((1 << i) - 1) ,如果要簡化對n的約束,請考慮(n - 1)的位:

如果n是16( = 1 << 4) ,那么n - 11516 (作為32位int )的位表示是:

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

因此,只有最低的4位在15中設置。如果你&另一個int,它只允許在結果中設置該數字的最后4位中的位,因此該值僅在0-范圍內15,所以就像在做% 16


但請注意,此等效性不適用於負的第一個操作數:

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

Ideone演示

整數/%的算術規則是:

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

hash -4和正n 8怎么樣?

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

因此模數保持符號。

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

要么:

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

所以在早期的Java中, %n hash必須是積極的開始。 現在哈希可能是負面的,更穩固和更好的散列。 所以這是java源代碼中這種微妙變化的合理原因。


背景:

2 n1,后跟n-1 0 s(二進制)。 2 n - 1是n-1 1 s。

因此,對於n為2的正冪,以及一些正數h:

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

另一種用法是計算int中的位數。 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