Search code examples
javabit-shiftprimitive-types

Why Java unsigned bit shifting for a negative byte is so strange?


I have a byte variable:

byte varB = (byte) -1; // binary view: 1111 1111

I want to see the two left-most bits and do an unsigned right shift of 6 digits:

varB = (byte) (varB >>> 6);

But I'm getting -1 as if it was int type, and getting 3 only if I shift for 30!

How can I work around this and get the result only with a 6-digit shift?


Solution

  • The reason is the sign extension associated with the numeric promotion to int that occurs when bit-shifting. The value varB is promoted to int before shifting. The unsigned bit-shift to the right does occur, but its effects are dropped when casting back to byte, which only keeps the last 8 bits:

    varB (byte)     : 11111111
    promoted to int : 11111111 11111111 11111111 11111111
    shift right 6   : 00000011 11111111 11111111 11111111
    cast to byte    : 11111111
    

    You can use the bitwise-and operator & to mask out the unwanted bits before shifting. Bit-anding with 0xFF keeps only the 8 least significant bits.

    varB = (byte) ((varB & 0xFF) >>> 6);
    

    Here's what happens now:

    varB (byte)     : 11111111
    promoted to int : 11111111 11111111 11111111 11111111
    bit-and mask    : 00000000 00000000 00000000 11111111
    shift right 6   : 00000000 00000000 00000000 00000011
    cast to byte    : 00000011