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ビットが設定されていました)。
回答:
(0 & -0) == 0
0は2の累乗ではないため、説明は完全に正確ではありません。それを言うより良い方法は
((n & -n) == n)
nが2の累乗、または2の累乗の負、またはゼロの場合。
nが2の累乗である場合、バイナリのnは単一の1の後にゼロが続きます。2の補数の-nは逆+1であるため、ビットは次のように整列します。
n 0000100...000
-n 1111100...000
n & -n 0000100...000
これが機能する理由を理解するには、2の補数を逆+1と見なします。 -n == ~n + 1
n 0000100...000
inverse n 1111011...111
+ 1
two's comp 1111100...000
1を足して2の補数を得るときは、1をずっと持ち歩くからです。
nが2の累乗†以外の場合、2の補数はそのキャリーのために設定された最高ビットを持たないため、結果はビットが欠落します。
†-またはゼロまたは2の累乗の負数...上部で説明されているように。
Random.java
読んでいないことを批判せずにタイトルの質問に答えていました。
n
が何であるかさえわかりません。私はこの仮定を確認していませんが、どういうわけか、adouble
が同じように動作するのではないかと疑っています。
n
この質問には「java」タグがあるので、タイプにかなり良い範囲を設定できます。 Java&
上double
またはfloat
Javaで定義されていません。整数型とブール値でのみ定義されます。以来-
ブール型のために定義されていない、我々は安全に推測できn
不可欠です。
2の補数であるため、-n
です~n+1
。
n
が2の累乗の場合、1ビットしか設定されていません。したがって~n
、1つを除くすべてのビットが設定されています。1を追加すると、特別なビットが再び設定され、それn & (that thing)
がに等しくなることが保証されn
ます。
そのJavaソースの前の行で0と負の数が除外されているため、逆も当てはまります。n
複数のビットが設定されている場合は、そのうちの1つがそのような最高のビットです。このビットは、それを「吸収」するためのより低いクリアビットがあるため、によって設定されません+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を再び除外します。
2の補数表現では、2の累乗のユニークな点は、k番目のビット(n = 2 ^ k)を除いて、すべて0ビットで構成されていることです。
base 2 base 10
000001 = 1
000010 = 2
000100 = 4
...
2の補数で負の値を取得するには、すべてのビットを反転して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の累乗であるすべての数値の場合、最下位のセットビットが唯一のセットビットです。他のすべての数値については、複数のビットセットがあり、その中で最下位のみが結果に設定されます。
これは、2の累乗とその2の補数の特性です。
たとえば、8を取ります。
8 = 0b00001000
-8 = 0b11111000
2の補数の計算:
Starting: 0b00001000
Flip bits: 0b11110111 (one's complement)
Add one: 0b11111000
AND 8 : 0b00001000
2の累乗の場合、1ビットのみが設定されるため、追加すると2 nのn番目のビットが設定されます(1つはn番目のビットに引き継がれます)。次に、2つの数字を入力すると、元の数字が返されます。AND
2の累乗ではない数値の場合、他のビットは反転されAND
ないため、元の数値は生成されません。
簡単に言うと、nが2の累乗である場合、つまり1ビットのみが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つの遺跡である手段のみビットの結果以来問題ではなく、オペレータがいること(&
0の場合になります2ビットの1つがゼロです):
000000...000010000...00000 <<< n
&
111111...111110000...00000 <<< -n
--------------------------
000000...000010000...00000 <<< n