if ((n & -n) == n) // i.e., n is a power of 2
// rest of the code
为什么是这样?
if ((n & -n) == n) // i.e., n is a power of 2
// rest of the code
为什么是这样?
(n & (n - 1)) == 0
也起作用(它删除了最低位,如果没有剩余的位,那么最初最多设置1位)。
Answers:
该描述并不完全准确,因为(0 & -0) == 0
0不是2的幂。更好的说法是
((n & -n) == n)
当n是2的幂或2的幂的负数或零时。
如果n是2的幂,则二进制中的n是单个1,后跟零。-n为2的补数是倒数+ 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的幂的负数...如顶部所述。
Random.java
我没有读过。
n
是; 我没有检查过这个假设,但是以某种方式怀疑a的double
行为方式是否相同。
n
由于这个问题带有“ java”标记,因此我们可以对类型进行很好的限制。 &
未在Javadouble
或float
Java上定义。它仅在整数类型和布尔值上定义。由于-
没有为布尔值定义,因此我们可以安全地推断出n
整数。
因为是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 & 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会将较低的1移到零所在的空间。
按位与(&)将再次过滤掉1。
用二的补码表示法,关于二的幂的唯一之处在于,它们由所有0位组成,除了第k位,其中n = 2 ^ k:
base 2 base 10
000001 = 1
000010 = 2
000100 = 4
...
要获得二进制补码的负值,请翻转所有位并加1。对于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列和第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的幂的数字,最低有效位是唯一的设置位。对于所有其他数字,将设置一个以上的位,其中结果中将仅设置最低有效位。
简而言之,如果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
是2的补数n
(这意味着唯一的1位保持原样,并且该位左侧的位为1,这实际上没有关系,因为AND运算符的结果为&
0两位之一为零):
000000...000010000...00000 <<< n
&
111111...111110000...00000 <<< -n
--------------------------
000000...000010000...00000 <<< n