回答:
>>
算術右シフト、>>>
論理右シフトです。
算術シフトでは、符号ビットが拡張されて数値の符号が保持されます。
例:-2は8ビットで表されます11111110
(最上位ビットは負の重みを持つため)。算術シフトを使用して1ビット右にシフトすると11111111
、または-1になります。ただし、論理右シフトは、値が符号付きの数値を表す可能性があることを気にしません。すべてを右に移動し、左から0で埋めるだけです。当社-2右は論理シフトを与える使用してビットをシフト01111111
。
2^k
、これが全員の答えであることは奇妙だと思います。ビットの文字列は数値ではなく、>>
常にビットの文字列で使用できます。ビットの文字列が果たす役割に関係なく、また「符号」の概念があるかどうかに関係なく、常に同じことを行います。オペランドが符号付き数として解釈されていない場合の議論で、すでに素晴らしい答えを拡張してもよいでしょうか?私の不満は理にかなっていますか?
String
としても捉えることができましたchar[]
。彼char
はaが数ではないと言っているのではありません。彼はそれが符号なしの数だと言っているだけです。私はそれが彼を失った場所だと思います。
>>>
符号なしシフトです。これは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が追加されます。
>>>
は署名されていないと思いますが、なぜ7>>32=7
ですか?一度に1つのシフトを実行するループを実行したところ、32
シフト後に、に戻ったことがわかりました7
。これが意味を持つ唯一の方法は、シフトアウトされた各数値について、「外側の円」に入ったということです。32
シフト後、それはなんとかその位置に戻ったが、明らかにそれはまだ意味をなさない。何が起こっている?
論理右シフト(v >>> n
)は、のビットがビット位置だけv
右にシフトされ、n
0が左側からシフトインされた値を返します。バイナリで書かれた8ビット値をシフトすることを検討してください:
01111111 >>> 2 = 00011111
10000000 >>> 2 = 00100000
ビットを符号なしの非負整数として解釈する場合、論理右シフトは、数値を対応する2の累乗で除算する効果があります。ただし、数値が2の補数表現である場合、論理右シフトは負の数を正しく除算しません。 。たとえば、ビットが符号なしの数値として解釈されると、上の2番目の右シフトは128から32にシフトします。しかし、Javaで一般的なように、ビットが2の補数で解釈されると、-128から32にシフトします。
したがって、2の累乗で除算するためにシフトする場合は、算術右シフト(v >> n
)が必要です。これは、inのビットがビット位置だけv
右にシフトされた値を返し、vの左端のビットのn
コピーが左側からシフトインされます。
01111111 >> 2 = 00011111
10000000 >> 2 = 11100000
ビットが2の補数表現の数値である場合、算術右シフトは2の累乗で除算する効果があります。左端のビットが符号ビットであるため、これは機能します。2の累乗で除算する場合は、符号を同じに保つ必要があります。
ビット演算子とビットシフト演算子の詳細を読む
>> Signed right shift
>>> Unsigned right shift
ビットパターンは左側のオペランドで与えられ、シフトする位置の数は右側のオペランドで与えられます。符号なし右シフト演算子は>>>
、ゼロを左端の位置にシフトします。
左端の位置>>
は符号拡張に依存します。
簡単な言葉で>>>
常にシフトゼロを左端位置に、一方>>
負の数と正の数の0の場合は1、すなわち数の符号に基づいてシフトします。
たとえば、正の数だけでなく負の数でも試してください。
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
System.out.println(Integer.MAX_VALUE + ": " + String.format("%32s", Integer.toBinaryString(Integer.MAX_VALUE)).replace(' ', '0'))
; Integer.MAX_VALUE: 01111111111111111111111111111111;
Integer.MIN_VALUE:10000000000000000000000000000000;
-1: 11111111111111111111111111111111;
0: 00000000000000000000000000000000;
1: 00000000000000000000000000000001
右シフト論理演算子(>>> N
)は、ビットをN桁だけ右にシフトし、符号ビットを破棄し、左端のNビットに0を埋め込みます。例えば:
-1 (in 32-bit): 11111111111111111111111111111111
>>> 1
操作後:
2147483647: 01111111111111111111111111111111
右シフト算術演算子(>> N
)も、ビットをN桁だけ右にシフトしますが、符号ビットを保持し、左端のNビットに1を埋め込みます。例えば:
-2 (in 32-bit): 11111111111111111111111111111110
>> 1
操作後:
-1: 11111111111111111111111111111111