5

Javaには、右シフト用の2つのビットシフト演算子があります。

>> shifts right, and is dependant on the sign bit for the sign of the result

>>> shifts right and shifts a zero into leftmost bits

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html

これはかなり単純なように思われるので、このコードがbarに-128の値を与えられたときに、fooに-2の値を生成する理由を誰かが私に説明できますか?

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

これが意味することは、8ビットバイト、左端の2ビットのマスクを取り、それらを右端の2ビットにシフトすることです。すなわち:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010

結果は実際には-2であり、これは

0b11111110

つまり。ゼロではなく1が左の位置にシフトされます

4

3 に答える 3

8

これは、&が実際に昇格を実行しているためです。これにより、非常にint多くの「1」ビットが残ります。次に、右にシフトし、左端の2ビットを0のままにしますが、バイトにキャストバックして左端のビットを無視します。

これは、操作を分離するとより明確になります。

public class Test
{
    public static void main(String[] args)
    {
        byte bar = -128;
        int tmp = (bar & ((byte)-64)) >>> 6;
        byte foo = (byte)tmp;
        System.out.println(tmp);
        System.out.println(foo);
    }
}

プリント

67108862
-2

したがって、ビット演算を再度実行するには、次のようにします。

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2

&操作から正しい結果が得られたとしても(その時点でキャストすることにより)、とにかく>>>最初のオペランドを最初にプロモートします。int

編集:解決策は、物事をマスクする方法を変更することです。-64でマスクする代わりに、128 + 64 = 192=0xc0でマスクします。

byte foo = (byte)((bar & 0xc0) >>> 6);

そうすれば、最上位の24ビットに1の負荷をかけるのではなく、実際には必要な2ビットだけを残すことができます。

于 2010-01-31T20:41:03.363 に答える
2

AFAIK、Javaでは、ほとんどの演算子(+、-、>>、&など)はsよりも小さいものでは機能しませんint。したがって、ビット単位でシフトし&、値をintバックグラウンドで暗黙的にキャストしbyteてから、外部で明示的にキャストして元に戻します。最後のキャストは、上位ビットのゼロを取り除きます。

期待する結果を得るには、intsでこれを実行してみてください。

于 2010-01-31T20:50:00.990 に答える
2

他の人が理由を教えてくれましたが、私はそれをさらに分解して、実際の問題に対する答えも提供します。

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

&演算子はすべてをintにプロモートするため、これは基本的に次のようになります。

byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);

バーが-128の場合、(int)barは0xFFFFFF80であり、0xFFFFFFC0 ...(0xFFFFFF80)で&'されます。次に、右に6桁シフトして、0x3FFFFFFEを取得します。

正解は本当に簡単です。

byte foo = (byte)((bar & 0xC0) >> 6);

barは&操作のintにプロモートされるため、そのintに残っているのは、元のバイトの上位2ビットだけです。次に、右に6ビットシフトして、バイトに戻します。

于 2010-01-31T20:51:43.770 に答える