The apparent oddity of Java

Java has 2 bit-shift 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 pretty simple, so someone can explain to me why this code, when set to -128 for a bar, produces a value of -2 for foo:

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

What you need to do is take the 8-bit byte, the mask of the leftmost two bits and transfer them to the rightmost 2 bits. I.e:

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

The result is actually -2, which is equal to

 0b11111110 

Those. 1s, not zeros, are shifted to the left

+4
source share
3 answers

This is because it actually performs promotion to int , which leaves a lot of “1” bits. Then you are shifted to the right, leaving the leftmost 2 bits equal to 0, but then ignoring those leftmost bits, discarding the bytes.

This becomes clearer when you highlight 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, repeat your bit arithmetic:

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

Even if you get the correct result from and the operation (by casting at this point), >>> will first support the first operand of int .

EDIT: The solution is to change how you mask things. Instead of masking at -64, masks instead of 128 + 64 = 192 = 0xc0 instead:

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

That way, you really only get the two bits you want, instead of having a load of 1 s in the most significant 24 bits.

+8
source

AFAIK, in Java most of the operators (+, -, →, &, etc.) cannot work on anything less than int s. That way, your bitwise shifts and & implicitly cast the values ​​to int in the background, and then back to byte through your explicit cast out. The last throw eliminates zeros in high bits.

To get the results you expect, try doing this on int s.

+2
source

Others told you why, but I will break it further and give an answer to the real problem.

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

Since the operator will promote everything in int, this is basically:

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

If bar is -128, then (int) bar is 0xFFFFFF80, which is then 0xFFFFFFC0 ... which is: 0xFFFFFF80, then you move this right 6 places to get: 0x3FFFFFFE

The correct answer is very simple:

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

bar advances to int for the operation, and so the only thing left in this int will be the top two bits of the original byte. Then shift it 6 bits to the right and convert it back to bytes.

+2
source

Source: https://habr.com/ru/post/1299897/


All Articles