30

Java の符号なし右シフト演算子 ">>>" の機能は理解できますが、なぜそれが必要なのですか? また、対応する符号なし左シフト演算子が必要ないのはなぜですか?

4

6 に答える 6

27

この演算子を使用すると、and をJava 言語にはない32 ビットおよび 64 ビットの符号なし>>>整数型として扱うことができます。intlong

これは、数値を表さないものをシフトする場合に便利です。intたとえば、それぞれintが画面上の 32 ピクセルをエンコードする 32ビット を使用して、白黒のビット マップ イメージを表すことができます。画像を右にスクロールする必要がある場合は、隣接するsintからのビットを簡単に配置できるように、an の左側のビットをゼロにすることをお勧めします。int

 int shiftBy = 3;
 int[] imageRow = ...
 int shiftCarry = 0;
 // The last shiftBy bits are set to 1, the remaining ones are zero
 int mask = (1 << shiftBy)-1;
 for (int i = 0 ; i != imageRow.length ; i++) {
     // Cut out the shiftBits bits on the right
     int nextCarry = imageRow & mask;
     // Do the shift, and move in the carry into the freed upper bits
     imageRow[i] = (imageRow[i] >>> shiftBy) | (carry << (32-shiftBy));
     // Prepare the carry for the next iteration of the loop
     carry = nextCarry;
 }

上記のコードは上位 3 ビットの内容に注意を払っていません>>>

<<符号付きデータ型と符号なしデータ型の左シフト演算は同じであるため、対応する演算子はありません。

于 2013-05-26T21:42:32.700 に答える
15

>>>は、2 つの (大きな) 整数の丸め平均を求める安全で効率的な方法でもあります。

int mid = (low + high) >>> 1;

整数highlowが最大のマシン整数に近い場合、上記は正しくなりますが、

int mid = (low + high) / 2;

オーバーフローのために間違った結果が得られる可能性があります。

単純な二分探索のバグを修正する の使用例を次に示します。

于 2014-03-18T01:27:15.877 に答える
3

基本的に、これは符号 (数値シフト) または符号なしシフト (通常はピクセル関連のもの) に関係しています。

とにかく、左シフトは符号ビットを処理しないので、同じことです (<<< と <<)...

いずれにせよ、私はまだ >>> を使う必要のある人に会ったことがありませんが、彼らが素晴らしいことをしていることは確かです。

先ほど見たように、>> 演算子は、シフトが発生するたびに上位ビットを以前の内容で自動的に埋めます。これにより、値の符号が保持されます。ただし、これは望ましくない場合もあります。たとえば、数値を表さないものをシフトする場合、符号拡張を実行したくない場合があります。この状況は、ピクセルベースの値とグラフィックスを操作している場合に一般的です。このような場合、通常、初期値が何であれ、ゼロを上位ビットにシフトする必要があります。これは符号なしシフトと呼ばれます。これを実現するには、Java の符号なし右シフト演算子 >>> を使用します。この演算子は、常にゼロを上位ビットにシフトします。

参考文献:

http://henkelmann.eu/2011/02/01/java_the_unsigned_right_shift_operator

http://www.java-samples.com/showtutorial.php?tutorialid=60

于 2013-05-26T21:42:15.017 に答える
3

The signed right-shift operator is useful if one has an int that represents a number and one wishes to divide it by a power of two, rounding toward negative infinity. This can be nice when doing things like scaling coordinates for display; not only is it faster than division, but coordinates which differ by the scale factor before scaling will differ by one pixel afterward. If instead of using shifting one uses division, that won't work. When scaling by a factor of two, for example, -1 and +1 differ by two, and should thus differ by one afterward, but -1/2=0 and 1/2=0. If instead one uses signed right-shift, things work out nicely: -1>>1=-1 and 1>>1=0, properly yielding values one pixel apart.

The unsigned operator is useful either in cases where either the input is expected to have exactly one bit set and one will want the result to do so as well, or in cases where one will be using a loop to output all the bits in a word and wants it to terminate cleanly. For example:

void processBitsLsbFirst(int n, BitProcessor whatever)
{
  while(n != 0)
  {
    whatever.processBit(n & 1);
    n >>>= 1;
  }
}

If the code were to use a signed right-shift operation and were passed a negative value, it would output 1's indefinitely. With the unsigned-right-shift operator, however, the most significant bit ends up being interpreted just like any other.

The unsigned right-shift operator may also be useful when a computation would, arithmetically, yield a positive number between 0 and 4,294,967,295 and one wishes to divide that number by a power of two. For example, when computing the sum of two int values which are known to be positive, one may use (n1+n2)>>>1 without having to promote the operands to long. Also, if one wishes to divide a positive int value by something like pi without using floating-point math, one may compute ((value*5468522205L) >>> 34) [(1L<<34)/pi is 5468522204.61, which rounded up yields 5468522205]. For dividends over 1686629712, the computation of value*5468522205L would yield a "negative" value, but since the arithmetically-correct value is known to be positive, using the unsigned right-shift would allow the correct positive number to be used.

于 2013-09-30T18:03:58.060 に答える