Java has 2 bitshift operators for right shifts:
>> 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
This seems fairly simple, so can anyone explain to me why this code, when given a value of -128 for bar, produces a value of -2 for foo:
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
What this is meant to do is take an 8bit byte, mask of the leftmost 2 bits开发者_开发问答, and shift them into the rightmost 2 bits. Ie:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010
The result actually is -2, which is
0b11111110
Ie. 1s rather than zeros are shifted into left positions
It's because the & is actually performing promotion to int
- which leaves an awful lot of "1" bits. You're then shifting right, leaving the leftmost 2 bits as 0, but then ignoring those leftmost bits by casting back to byte.
This becomes clearer when you separate out the operations:
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);
}
}
prints
67108862
-2
So to do your bit arithmetic again:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2
Even if you get the right result out of the & operation (by casting at that point), >>>
will promote the first operand to int
first anyway.
EDIT: The solution is to change how you mask things. Instead of masking by -64, mask by just 128+64=192=0xc0 instead:
byte foo = (byte)((bar & 0xc0) >>> 6);
That way you really only get left with the two bits you want, instead of having a load of 1s in the most significant 24 bits.
AFAIK, in Java most operators (+,-,>>,& etc.) can't work on anything smaller than int
s. So, your bitwise shifts and &
are implicitly casting the values into int
in the background and then back into byte
by your explicit cast outside. The last cast gets rid of the zeroes in the higher bits.
To get results you would expect, try doing this on int
s.
Others have told you why but I'll break it down further and provide an answer to the real problem, too.
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
Since the & operator will promote everything to int, what this does is essentially:
byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);
If bar is -128 then (int)bar is 0xFFFFFF80 which is then &'ed with 0xFFFFFFC0... which is: 0xFFFFFF80, you then shift that right 6 places to get: 0x3FFFFFFE
The right answer is really simple:
byte foo = (byte)((bar & 0xC0) >> 6);
bar is promoted to an int for the & operation so the only thing left in that int will be the top two bits of the original byte. Then shift it right 6 bits and convert it back to bytes.
精彩评论