Line 294 of java.util.Random source说
if ((n & -n) == n) // i.e., n is a power of 2
// rest of the code
为什么会这样?
答案 0 :(得分:95)
因为在2的补码中,-n
是~n+1
。
如果n
是2的幂,那么它只设置一个位。所以~n
除了那个之外都设置了所有位。添加1,然后再次设置特殊位,确保n & (that thing)
等于n
。
反过来也是如此,因为该Java源中的前一行排除了0和负数。如果n
设置了多个位,那么其中一个位是最高位。这个位不由+1
设置,因为有一个较低的清除位来“吸收”它:
n: 00001001000
~n: 11110110111
-n: 11110111000 // the first 0 bit "absorbed" the +1
^
|
(n & -n) fails to equal n at this bit.
答案 1 :(得分:48)
描述并不完全准确,因为(0 & -0) == 0
但0不是2的幂。更好的说法是
((n & -n) == n)
当n是2的幂时,或2的幂的负数,或者为零。
如果n是2的幂,则二进制中的n是单个1,后跟零。 -in的二进制补码是反+ 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的幂†那么结果将会丢失一点,因为由于该进位,两个补码不会设置最高位。
† - 或零或2的幂的负数......如顶部所述。
答案 2 :(得分:13)
您需要将值视为位图,以了解为什么这是真的:
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
因此,只有当两个字段均为1时才会出现1。
现在-n做了2的补充。它会将0
更改为1
并添加1。
7 = 00000111
-1 = NEG(7) + 1 = 11111000 + 1 = 11111001
然而
8 = 00001000
-8 = 11110111 + 1 = 11111000
00001000 (8)
11111000 (-8)
--------- &
00001000 = 8.
只有2的幂才(n & -n)
为n
这是因为2的幂表示为零的长海中的单个设置位。
否定将产生完全相反的,在1的海洋中产生单个零(在曾经是1的地方)。添加1会将较低的一个移动到零所在的空间
按位和(&)将再次过滤掉。
答案 3 :(得分:8)
在二进制补码表示中,关于2的幂的独特之处在于它们由全0位组成,除了第k位,其中n = 2 ^ k:
base 2 base 10
000001 = 1
000010 = 2
000100 = 4
...
要获得二进制补码的负值,请翻转所有位并添加一位。对于2的幂,这意味着你在左边得到一堆1,包括正值的1位,然后是右边的一堆0:
n base 2 ~n ~n+1 (-n) n&-n
1 000001 111110 111111 000001
2 000010 111101 111110 000010
4 000100 111011 111100 000100
8 001000 110111 111000 001000
您可以很容易地看到第2列和第2列的结果4将与第2列相同。
如果你看一下这个图表中缺少的其他值,你就可以看出为什么除了2的权力之外没有任何其他值:
n base 2 ~n ~n+1 (-n) n&-n
1 000001 111110 111111 000001
2 000010 111101 111110 000010
3 000011 111100 111101 000001
4 000100 111011 111100 000100
5 000101 111010 111011 000001
6 000110 111001 111010 000010
7 000111 111000 111001 000001
8 001000 110111 111000 001000
n& -n将(对于n> 0)仅设置1位,并且该位将是n中的最低有效位设置位。对于所有2的幂次数,最低有效设置位是唯一的设置位。对于所有其他数字,有多个位集,其中只有最低有效位将在结果中设置。
答案 4 :(得分:4)
它的权力为2及其two's complement。
例如,取8:
8 = 0b00001000
-8 = 0b11111000
计算二者的补码:
Starting: 0b00001000
Flip bits: 0b11110111 (one's complement)
Add one: 0b11111000
AND 8 : 0b00001000
对于2的幂,只有一位将被设置,因此添加将导致设置2 n 的n th 位(一个人继续携带到n th 位。然后当你AND
这两个数字时,你会得到原来的数据。
对于非幂2的数字,其他位不会被翻转,因此AND
不会产生原始数字。
答案 5 :(得分:4)
简单地说,如果n是2的幂,则意味着只有一位设置为1而其他位为0:
00000...00001 = 2 ^ 0
00000...00010 = 2 ^ 1
00000...00100 = 2 ^ 2
00000...01000 = 2 ^ 3
00000...10000 = 2 ^ 4
and so on ...
并因为-n
是n
的2的补码(这意味着唯一的1位保持不变,并且该位左侧的位位于1,实际上不是没关系,因为如果两个位中的一个为零,AND运算符&
的结果将为0):
000000...000010000...00000 <<< n
&
111111...111110000...00000 <<< -n
--------------------------
000000...000010000...00000 <<< n
答案 6 :(得分:0)
通过示例显示:
8 in hex = 0x000008
-8 in hex = 0xFFFFF8
8&amp; -8 = 0x000008