为什么如果 (n & -n) == n 那么 n 是 2 的幂?

2022-08-31 12:06:18

java.util.随机源的第294行

if ((n & -n) == n) // i.e., n is a power of 2
    // rest of the code

这是为什么呢?


答案 1

因为在 2 的补码中,是 。-n~n+1

如果 是 2 的幂,则它只设置了一个位。因此,除了那一个之外,所有位都设置好了。添加 1,然后再次设置特殊位,确保等于 。n~nn & (that thing)n

反之亦然,因为 0 和负数被该 Java 源中的前一行排除。如果设置了多个位,则其中一个是最高的此类位。这个位不会被 设置,因为有一个较低的清除位来“吸收”它:n+1

 n: 00001001000
~n: 11110110111
-n: 11110111000  // the first 0 bit "absorbed" the +1
        ^
        |
        (n & -n) fails to equal n at this bit.

答案 2

描述并不完全准确,因为 0 不是 2 的幂。更好的说法是(0 & -0) == 0

((n & -n) == n)当 n 是 2 的幂,或 2 的幂的负数,或零。

如果 n 是 2 的幂,则二进制中的 n 是单个 1 后跟零。二进制补数中的 -n 是逆 + 1,因此位排列在一起

 n      0000100...000
-n      1111100...000
 n & -n 0000100...000

要了解为什么这有效,请考虑二的补码为逆+ 1,-n == ~n + 1

n          0000100...000
inverse n  1111011...111
                     + 1
two's comp 1111100...000

因为当你在添加一个以获得两个的补充时,你一直带着一个。

如果 n 不是 2 的幂†那么结果会丢失一点,因为由于该携带,两者的补码不会设置最高位。

† - 或零或二次幂的负数...如顶部所述。


推荐