Javaの演算子>>>
と>>
の違いは何ですか?
>>
は算術右シフト、>>>
は論理右シフトです。
算術シフトでは、符号ビットは数の符号を保持するために拡張されます。
たとえば、8ビットで表される-2は11111110
になります(最上位ビットには負の重みがあるため)。算術シフトを使用して1ビット右にシフトすると、11111111
、または-1になります。ただし、論理右シフトでは、値が符号付き数値を表す可能性があることを気にする必要はありません。単にすべてを右に移動し、左から0で埋めます。論理シフトを使用して-2を右に1ビットシフトすると、01111111
が得られます。
>>>
は符号なしシフトです。 0が挿入されます。>>
は符号付きで、符号ビットを拡張します。
シフト演算子には、左シフト
<<
、符号付き右シフト>>
、および符号なし右シフト>>>
があります。
n>>s
の値は、符号拡張を付けてn
右シフトしたs
ビット位置です。
n>>>s
の値は、ゼロ拡張でn
右シフトしたs
ビット位置です。
System.out.println(Integer.toBinaryString(-1));
// prints "11111111111111111111111111111111"
System.out.println(Integer.toBinaryString(-1 >> 16));
// prints "11111111111111111111111111111111"
System.out.println(Integer.toBinaryString(-1 >>> 16));
// prints "1111111111111111"
もっと明確にするため
System.out.println(Integer.toBinaryString(121));
// prints "1111001"
System.out.println(Integer.toBinaryString(121 >> 1));
// prints "111100"
System.out.println(Integer.toBinaryString(121 >>> 1));
// prints "111100"
符号付きシフトと符号なしシフトの両方が正なので、左端のビットに0が加算されます。
>>>
は常に左端のビットに0を入れますが、>>
はその符号によって、1または0を入れます。
論理右シフト(v >>> n
)は、v
内のビットがn
ビット位置だけ右にシフトされ、0が左側からシフトインされた値を返します。バイナリで書かれた8ビット値をシフトすることを考えてください。
01111111 >>> 2 = 00011111
10000000 >>> 2 = 00100000
ビットを符号なしの非負整数として解釈すると、論理右シフトは対応する2の累乗で数値を除算する効果があります。ただし、数値が2の補数表現の場合、論理右シフトは負の数を正しく除算しません。 。たとえば、ビットが符号なし数値として解釈されると、上の2番目の右シフトは128から32にシフトします。しかし、Javaでよく見られるように、ビットが2の補数で解釈されると、-128から32にシフトします。
したがって、2のべき乗で除算するためにシフトする場合は、算術右シフト(v >> n
)が必要です。 v
のビットがn
ビット位置だけ右にシフトされ、vの左端のビットのコピーが左側からシフトインされた値が返されます。
01111111 >> 2 = 00011111
10000000 >> 2 = 11100000
ビットが2の補数表現の数値の場合、算術右シフトは2の累乗で除算する効果があります。これは、左端のビットが符号ビットなので機能します。 2のべき乗で割ると、符号は同じになります。
ビット演算子とビットシフト演算子 についてもっと読む
>> Signed right shift
>>> Unsigned right shift
ビットパターンは左側のオペランドによって、そしてシフトする位置の数は右側のオペランドによって与えられます。符号なし右シフト演算子>>>
はzeroを左端の位置にシフトします 、
>>
の後の左端の位置は符号の拡張子によって異なります。
簡単に言うと、>>>
は常にzeroを左端の位置にシフトします に対して>>
は、負の数の場合は1、正の数の場合は0です。
例えば、正の数だけでなく負の数で試してください。
int c = -153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.println(Integer.toBinaryString(c <<= 2));
System.out.println();
c = 153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
出力:
11111111111111111111111111011001
11111111111111111111111101100100
111111111111111111111111011001
11111111111111111111111101100100
100110
10011000
100110
10011000
右シフト論理演算子(>>> N
)は、符号ビットを破棄し、左端のNビットに0を埋めて、ビットをN位置だけ右にシフトします。例えば:
-1 (in 32-bit): 11111111111111111111111111111111
>>> 1
操作の後になります:
2147483647: 01111111111111111111111111111111
右シフト算術演算子(>> N
)もビットをN桁分右にシフトしますが、符号ビットを保存し、左端のNビットに1を埋め込みます。例えば:
-2 (in 32-bit): 11111111111111111111111111111110
>> 1
操作の後になります:
-1: 11111111111111111111111111111111