21

私は右シフト操作で負の数に混乱しています、ここではコードです。Java:右シフトマイナス番号

int n = -15; 
System.out.println(Integer.toBinaryString(n)); 
int mask = n >> 31; 
System.out.println(Integer.toBinaryString(mask)); 

、結果がある:

11111111111111111111111111110001 
11111111111111111111111111111111 

右31ない1(符号ビット)によって負の数をシフトする理由?

+2

ところで、あなたは '>>> -1'を使うことができ、' int'型と 'long'型で動作します。 –

答えて

30

Javaで何の符号なしのデータ型が存在しないので、右シフトの2種類がありますarithmetic shift>>logical shift>>>http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

算術シフト>>は符号ビットを保持します。
Arithmetic shift

符号なしシフト>>>は(従って0 Sを充填する)符号ビットを保持しないであろう。
Logical shift

(ウィキペディアからの画像)


ところで、算術左シフト、論理左シフトの両方が同じ結果を持っているので、一つだけ左シフト<<があります。

+0

** '10101010 << 1' **の場合はどうなりますか? ** '11010100' **または**' 01010100' **? –

+0

@AurélienOomsそれは右に '0'を埋め込む左シフトです。 –

+1

私は、つまり、 ''ところで、算術シフトと論理シフトの両方が同じ結果になるので、左シフトは本当に本当ですか? –

12

演算子>>符号付き右シフトは、すべてのビットを指定された回数右にシフトします。重要:>>は、シフト後の左端のビットに左端の符号ビット(Most Significant Bit MSB)を埋めます。これは、符号拡張と呼ばれ、には、右にシフトすると負の符号が保持されます。

以下

これは(1バイトのために)どのように動作するかを示すために例と私の概略図である。

例:2の補数形式で

i = -5 >> 3; shift bits right three time 

ファイブは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ビットがあるため、各シフト符号ビットが保存されるに一つであり、各ビットは右すぎです。私は書いたこの3ビットはすべて符号(データではない)のために、符号はに伝搬されます。

また、右の3つの右シフトのために、ほとんどの3ビットが失われます。

右の2つの矢印の間のビットは、-5の前のビットから公開されています。

正の数の例も書いてもいいと思います。次の例では、5 >> 3で、5は、1つのバイトが、私はサインはそう左端の3ゼロビットに署名する予定です、伝播され書き込みを再び参照してください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 

です。

これはオペレータです>>符号付き右シフトは、左オペランドの符号を保持します。

[解答]
あなたのコードでは、あなたはとても右手最も31ビットを緩め、結果は実際に-1大きさがあるすべてのビット1でいる>>演算子を使用して31回右へ-15を移します。

このように、-1 >> nはステートメントではないことに気づいていますか?
私は1つのi = -1 >> nを行う場合には、Javaコンパイラによってi = -1に最適化されなければならないと考えているが、それは別の問題である

次に、より多くの右シフト演算は、符号なし呼ば>>>利用可能であるJavaのいずれかで知って興味深いものになるだろう右シフト。論理的に動作し、シフト操作ごとに左からゼロを埋めます。だから、右シフトごとに符号なし右シフト>>>演算子を負の数と正の数の両方に使用すると、常に最も左の位置にゼロビットが得られます。

例:以下

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(グラフィックスプログラミング)では役に立ちますが、私はそれを使用していませんでしたが、過去にはどこかでそれを読んでいました。

私はこれを読むことをお勧めします:Difference between >>> and >>>>は右に算術シフト、>>>は論理的に右にシフトします。

編集

符号なし右に関するいくつかの興味深いオペレータ>>>オペレータをシフトします。

  • 符号なし右シフト演算>>>、その右オペランドで指定されたビットの数でゼロ0拡張と右シフトの左オペランドである純粋な値を生成します。

  • >>と同じように、オペレータ>>>も例外をスローしません。

  • 符号なし右シフト演算子の各オペランドの型は、整数データ型である必要があります。そうでない場合、コンパイル時エラーが発生します。

  • >>>演算子は、そのオペランドで型変換を実行できます。算術バイナリ演算子とは異なり、各オペランドは独立して変換されます。オペランドの型がbyte、short、またはcharの場合、そのオペランドは演算子の値が計算される前にintに変換されます。

  • 符号なし右シフト演算子によって生成される値の型は、その左のオペランドの型です。LEFT_OPERAND >>> RHIGT_OPERAND

  • 左オペランドの変換タイプがintである場合、右オペランドの値のみ5つの最下位ビットは、シフト距離として使用されます。 (2 = 32ビット= INTにおけるビットの数である
    だから、シフト距離は、ここ31

    介し範囲0であり、r >>> sした値と同じです。

    s==0 ? r : (r >> s) & ~(-1<<(32-s)) 
    
  • 左オペランドの型は、右オペランドの値のわずか6つの最下位ビットは、シフト距離として使用され、長い場合。( = 64ビットであります=長いビット数ここ)

    r >>> sした値は、次のように同じである。

    s==0 ? r : (r >> s) & ~(-1<<(64-s)) 
    

興味深いリファレンス:[Chapter 4] 4.7 Shift Operators

+0

実際には '1を置く'というわけではありませんが、記号ビットをそのまま保持します。 – EJP

+1

より簡単な答えはより正確で、より多くの助けになります。オペレータは、オペランドが負であるか正であるかを調べることなく、次に2つの異なることを見ます。 – EJP

+0

ポイントに固執し、性格を守ってください。あなたの説明は、必要なだけ2倍複雑で、@ AlvinWongの答えに対するあなたのコメントで判断すると、それでもなぜそれが理解できないのですか。 – EJP

3

>>を算術右シフトとして定義されているので、それは記号を保存します。予想される効果を得るには、論理右シフト、>>>演算子を使用します。

+0

私はあなたに一言で書いてみようとしていました*良い看板を保つ*。 –