Behaviour of unsigned right shift applied to byte variable
Consider the following snip of java code
byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);
output:
c=0xff
d=0xff
expected output:
c=0x0f
how?
as b in binary 1111 0001
after unsi开发者_Go百科gned right shift 0000 1111
hence 0x0f
but why is it 0xff
how?
The problem is that all arguments are first promoted to int
before the shift operation takes place:
byte b = (byte) 0xf1;
b
is signed, so its value is -15.
byte c = (byte) (b >> 4);
b
is first sign-extended to the integer -15 = 0xfffffff1
, then shifted right to 0xffffffff
and truncated to 0xff
by the cast to byte
.
byte d = (byte) (b >>> 4);
b
is first sign-extended to the integer -15 = 0xfffffff1
, then shifted right to 0x0fffffff
and truncated to 0xff
by the cast to byte
.
You can do (b & 0xff) >>> 4
to get the desired effect.
I'd guess that b
is sign extended to int
before shifting.
So this might work as expected:
(byte)((0x000000FF & b)>>4)
According to Bitwise and Bit Shift Operators:
The unsigned right shift operator ">>>" shifts a zero into the leftmost position, while the leftmost position after ">>" depends on sign extension.
So with b >> 4
you transform 1111 0001
to 1111 1111
(b is negative, so it appends 1
) which is 0xff
.
Java tries to skimp on having explicit support for unsigned basic types by defining the two different shift operators instead.
The question talks about unsigned right shift, but the examples does both (signed and unsigned), and shows the value of the signed shift (>>).
Your calculations would be right for unsigned shift (>>>).
The byte operand is promoted to an int before the shift.
See https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19
Unary numeric promotion (§5.6.1) is performed on each operand separately. (Binary numeric promotion (§5.6.2) is not performed on the operands.)
And https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.1
Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).
byte b=(byte) 0xf1;
if (b<0)
d = (byte) ((byte) ((byte)(b>>1)&(byte)(0x7F)) >>>3);
else
d = (byte)(b>>>4);
First, check the value: If the value is negative. Make one right shift, then & 0x7F, It will be changed to positive. then you can make the rest of right shift (4-1=3) easily.
If the value is positive, make all right shift with >>4 or >>>4. It does'nt make no difference in result nor any problem of right shift.
精彩评论