web-dev-qa-db-ja.com

(n&-n)== nの場合、nが2の累乗であるのはなぜですか?

Java.util.Randomソースの294行目

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

どうしてこれなの?

84
David Weng

(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

2の補数を得るために1を追加するときは、1つを最後まで実行するためです。

Nが2の累乗†以外の場合、2の補数はそのキャリーのために設定された最高ビットを持たないため、結果はビットが欠落します。

†-またはゼロまたは2の累乗の負数...上部で説明されているように。

48
Mike Samuel

2の補数では、_-n_は_~n+1_であるためです。

nが2の累乗である場合、1ビットしか設定されていません。したがって、_~n_には、1つを除くすべてのビットが設定されています。 1を追加すると、特別なビットが再度設定され、n & (that thing)nと等しくなるようになります。

そのJavaソースの前の行で0と負の数が除外されているため、逆も当てはまります。 nに複数のビットが設定されている場合、そのうちの1つがそのような最高のビットです。このビットはnot _+1_によって設定されます。これは、それを「吸収」するためのより低いクリアビットがあるためです。

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

これが当てはまる理由を確認するには、値をビットマップとして確認する必要があります。

1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

したがって、両方のフィールドが1の場合にのみ、1が出力されます。

これで、-nは2の補数を実行します。すべての01に変更し、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を再び除外します。

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の累乗であるすべての数値の場合、最下位のセットビットが唯一のセットビットです。他のすべての数値については、複数のビットセットがあり、その中で最下位のみが結果に設定されます。

8
Eclipse

簡単に言うと、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 ...

そして-nnの2の補数です(つまり、1である唯一のビットはそのまま残り、そのビットの左側のビットは1になります。これは、の結果から実際には問題ではありません。 AND演算子& 2ビットのいずれかがゼロの場合は0になります):

000000...000010000...00000 <<< n
&
111111...111110000...00000 <<< -n
--------------------------
000000...000010000...00000 <<< n
4
Eng.Fouad

これは2の累乗とその 2の補数 の特性です。

たとえば、8を取ります。

8  = 0b00001000

-8 = 0b11111000

2の補数の計算:

Starting:  0b00001000
Flip bits: 0b11110111  (one's complement)
Add one:   0b11111000  

AND 8    : 0b00001000

2の累乗の場合、1ビットのみが設定されますので、追加するとnが発生しますth 2のビットn 設定する(1つはnに運び続けるth ビット)。次に、2つの数値をANDすると、元の数値が返されます。

2の累乗ではない数値の場合、他のビットは反転されないため、ANDは元の数値を生成しません。

4
Austin Salonen

例を通して示されている:

16進数で8 = 0x000008

-8の16進数= 0xFFFFF8

8&-8 = 0x000008

0
John B