In Java, -4 >> 2 gives -1 but -5 >> 2 gives -2. Can anybody explain why? Here is a sample code:
byte r=-5;
r>>=2;
System.out.println(r);
Also in this scenario >> and >>> operators give the same answer. Can anyone explain that as well?
In Java, -4 >> 2 gives -1 but -5 >> 2 gives -2. Can anybody explain why? Here is a sample code:
byte r=-5;
r>>=2;
System.out.println(r);
Also in this scenario >> and >>> operators give the same answer. Can anyone explain that as well?
You can take a look at the bits. Using two's complement notation, the bits for -4
and -5
are, showing only the last 8 bits for brevity:
-4: 1111 1100
-5: 1111 1011
Bit shifting to the right 2 positions, with sign extension:
-4 >> 2: 1111 1111 (-1)
-5 >> 2: 1111 1110 (-2)
Normally, you think of >>>
not using sign extension, and this is true, but in this case:
r >>>= 2;
... the value r
is promoted to int
for the bit-shift operation using binary numeric promotion, but the compound assignment operator casts the returned value back to byte
, and the shifted-in zero "disappears".
byte r = -5; // 1111 1100
r >>>= -2; // promoted to int: 11111111 11111111 11111111 11111010
// bit shift: 00111111 11111111 11111111 11111110
// cast back to byte: 11111110 (-2)
The JLS, Section 15.26.2, talks about the casting operation done in compound assignment operators:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
That is, in this case, the result of the bit-shift is casted back to byte
.
The same cast-back-to-byte operation occurs when the value of r
is -4
.
Note that if the assignment part wasn't done, then you wouldn't see the same answer, because it wouldn't cast the result back to byte
:
System.out.println(r >>> 2);
Then you would see:
1073741822
Can anybody explain why (-4 >> 2 is -1, and -5 >> 2 is -2)?
Binary -4 byte looks like this: 11111100
. When you shift it right while extending the sign, you get 11111111
(the ones on the left is sign extension, i.e. keeping the sign bit while shifting left). This is -1
in two's complement representation.
Binary -5 byte looks like this: 11111011
. When you shift it right while extending the sign, you get 11111110
(again, the ones on the left is sign extension). This is -2.
>>
and>>>
operators give the same answer. Can anyone explain that as well?
Shifting is performed in integers. When you use >>>
to shift -4
without sign extension, you get 00111111111111111111111111111111
. When you convert it to byte
, you chop off the top 24 bits, ending up with the lower eight bits all set to 1
. Same goes for >>>
of -5
.
In the case of negative numbers, in memory they are stored using a technique called two's complement. In this example, 5 is: 0...0101 (i am removing a lot of 0's for sake of length so when you shift 0101 twice you get:
0101 >> 0010
0010 >> 0001
0001 is 1
in two's complement you have 1...1011 (inverse all the bits then add a binary 1) so when you shift 1011 you have
1011 >> 1101 (we carry the other 1's)
1101 >> 1110 (we carry the other 1's)
1...1110 is the negative for -2
Java uses the two's complement format to represent negative numbers.
-5 is represented as 11111011
in binary which when right-bitshifted 2 bits over becomes 11111110
, which is -2. Similarly, -4 is represented as 11111100
, which when right-bitshifted by 2 becomes 11111111
, which is -1 in decimal.
The reason >>
and >>>
appear to be the same is because the >>>
operator is a logical right shift on integers, not bytes. Therefore java is type casting r to an int before it preforms the logical shift and then truncating the bitstring to only the least significant 8 bits. Because the integer representation of -5 is 11111111111111111111111111111011
and the logical shift 2 right is 11111111111111111111111111111110
which is typecast to a byte of 11111110
, which is -2.
If you try the following code you see the results:
byte r = -5;
System.out.println(r >> 2);
System.out.println(r >>> 2);
r>>>=2;
System.out.println(r);
The byte -4 == 0xFC. If you shift that arithmetically right (i.e. preserving the sign bit) by 2 bits you get 0xFF, which is -1.
-5 == 0xFB. If you shift that arithmetically right by 2 bits you get 0xFE, which is -2.