Signed right shift>>
と呼ばれる演算子は、指定された回数だけすべてのビットを右にシフトします。重要なのは 、シフト後に左端の符号ビット (Most Significant Bit MSB) を左端のビットに埋めることです。これは符号拡張と呼ばれ、負の数を右にシフトしたときに負の数 の符号を保持するのに役立ちます。>>
以下は、これがどのように機能するかを示す例を図で表したものです (1 バイトの場合):
例:
i = -5 >> 3; shift bits right three time
2 の補数形式の 5 は1111 1011
メモリ表現:
MSB
+----+----+----+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
+----+----+----+---+---+---+---+---+
7 6 5 4 3 2 1 0
^ This seventh, the left most bit is SIGN bit
そして以下は、どのように>>
機能しますか?あなたがするとき-5 >> 3
this 3 bits are shifted
out and loss
MSB (___________)
+----+----+----+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
+----+----+----+---+---+---+---+---+
| \ \
| ------------| ----------|
| | |
▼ ▼ ▼
+----+----+----+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
The sign is
propagated
注意: 各シフトで符号ビットが保持され、各ビットも右にあるため、左端の 3 ビットは 1 です。この 3 つのビットはすべて符号 (データではない) によるものであるため、 符号が伝搬されます。
また、右に 3 回シフトするため、ほとんどの 3 ビットが失われます。
右の 2 つの矢印の間のビットは、 の前のビットから露出しています-5
。
正の数の例も書いたらいいと思います。次の例は5 >> 3
、5 は 1 バイトです。0000 0101
this 3 bits are shifted
out and loss
MSB (___________)
+----+----+----+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
+----+----+----+---+---+---+---+---+
| \ \
| ------------| ----------|
| | |
▼ ▼ ▼
+----+----+----+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+----+----+----+---+---+---+---+---+
(______________)
The sign is
propagated
もう一度書きます符号は伝搬されます, したがって、左端の 3 つのゼロは符号ビットによるものです.
したがって、これは演算子>>
符号付き右シフトが行うことであり、左オペランドの符号を保持します。
[あなたの答え]
あなたのコードでは、演算子を使用-15
して右にシフトするため、右端のビットが失われ、結果は実際に大きさのすべてのビットになります。31
>>
31
1
-1
-1 >> n
In this wayは not ステートメントと同等であることに気付き ましたか。
もしそうなら、Javaコンパイラによってi = -1 >> n
最適化されるべきだと思いますが、それは別の問題ですi = -1
次に、Java でUnsigned Right Shift>>>
と呼ばれる右シフト演算子がもう 1 つ利用可能であることを知っておくと興味深いでしょう。そして、それは論理的に機能し、シフト操作ごとに左からゼロを埋めます。したがって、負数と正数の両方に符号なし右シフト演算子を使用すると、右シフトごとに常に左端の位置にゼロビットが得られます。>>>
例:
i = -5 >>> 3; Unsigned shift bits right three time
以下は、式がどのように-5 >>> 3
機能するかを示す私の図ですか?
this 3 bits are shifted
out and loss
MSB (___________)
+----+----+----+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
+----+----+----+---+---+---+---+---+
| \ \
| ------------| ----------|
| | |
▼ ▼ ▼
+----+----+----+---+---+---+---+---+
| 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
These zeros
are inserted
そして、お気づきでしょう: 今回は、符号ビットが伝搬されたとは書いていませんが、実際には>>>
演算子がゼロを挿入していると書いています。したがって>>>
、符号を保持せず、代わりに論理右シフトを行います。
私の知る限り、符号なし右シフトは VDU (グラフィックス プログラミング) で役立ちますが、使用したことはありませんが、過去のどこかで読んだことがあります。
これを読むことをお勧めします: >>> と >> の違い:>>
算術右シフト、>>>
論理右シフトです。
編集:
Unsigned Right Shift Operator >>>
operator について興味深いものがあります。
符号なし右シフト演算子は、右オペランドで指定されたビット数だけ拡張>>>
ゼロで左オペランドを右シフトした純粋な値を生成します。0
and と同様>>
に<<
、 operator>>>
も operator が例外をスローすることはありません。
符号なし右シフト演算子の各オペランドの型は、整数データ型である必要があります。そうしないと、コンパイル時エラーが発生します。
>>>
演算子は、そのオペランドに対して型変換を実行できます。算術二項演算子とは異なり、各オペランドは個別に変換されます。オペランドの型が byte、short、または char の場合、そのオペランドは、演算子の値が計算される前に int に変換されます。
符号なし右シフト演算子によって生成される値の型は、その左オペランドの型です。LEFT_OPERAND >>> RHIGT_OPERAND
左オペランドの変換後の型が intの場合、右オペランドの値の最下位 5 ビットのみがシフト距離として使用されます。(つまり、2 5 = 32 ビット = int のビット数)
、シフト距離は 0 から 31 の範囲になります。
ここで、によって生成される値r >>> s
は次と同じです。
s==0 ? r : (r >> s) & ~(-1<<(32-s))
左オペランドの型が long の場合、右オペランドの値の最下位 6 ビットのみがシフト距離として使用されます (つまり、2 5 = 64 ビット = long のビット数) 。
ここで、によって生成される値r >>> s
は次と同じです。
s==0 ? r : (r >> s) & ~(-1<<(64-s))
興味深いリファレンス: [第 4 章] 4.7 シフト演算子