Signed vs unsigned shift and Expressing the power of 2


Signed vs unsigned shift

In Java, all number primitives are signed. For example, an int always represent values from [-2^31 - 1, 2^31], keeping the first bit to sign the value - 1 for negative value, 0 for positive.

Basic shift operators >> and << are signed operators. They will conserve the sign of the value.

But it is common for programmers to use numbers to store unsigned values. For an int, it means shifting the range to [0, 2^32 - 1], to have twice as much value as with a signed int.

For those power users, the bit for sign as no meaning. That's why Java added >>> a left-shift operator, disregarding that sign bit.

 initial value: 4 ( 100)
 signed left-shift: 4 << 1 8 ( 1000)
 signed right-shift: 4 >> 1 2 ( 10)
 unsigned right-shift: 4 >>> 1 2 ( 10)
 initial value: -4 ( 11111111111111111111111111111100)
 signed left-shift: -4 << 1 -8 ( 11111111111111111111111111111000)
 signed right-shift: -4 >> 1 -2 ( 11111111111111111111111111111110)
 unsigned right-shift: -4 >>> 1 2147483646 ( 1111111111111111111111111111110)

Why is there no <<< ?

This comes from the intended definition of right-shift. As it fills the emptied places on the left, there are no decision to take regarding the bit of sign. As a consequence, there is no need for 2 different operators


Expressing the power of 2

For expressing the power of 2 (2^n) of integers, one may use a bitshift operation that allows to explicitly specify the n.

The syntax is basically:

int pow2 = 1<<n;

Examples:

int twoExp4 = 1<<4; //2^4
int twoExp5 = 1<<5; //2^5
int twoExp6 = 1<<6; //2^6
...
int twoExp31 = 1<<31; //2^31

This is especially useful when defining constant values that should make it apparent, that a power of 2 is used, instead of using hexadecimal or decimal values.

int twoExp4 = 0x10; //hexadecimal
int twoExp5 = 0x20; //hexadecimal
int twoExp6 = 64; //decimal
...
int twoExp31 = -2147483648; //is that a power of 2?

A simple method to calculate the int power of 2 would be

int pow2(int exp){
 return 1<<exp;
}

Packing / unpacking values as bit fragments

It is common for memory performance to compress multiple values into a single primitive value. This may be useful to pass various information into a single variable

For example, one can pack 3 bytes - such as color code in RGB - into an single int.

Packing the values

// Raw bytes as input
byte[] b = {(byte)0x65, (byte)0xFF, (byte)0x31};
 
// Packed in big endian: x == 0x65FF31
int x = (b[0] & 0xFF) << 16 // Red
 | (b[1] & 0xFF) << 8 // Green
 | (b[2] & 0xFF) << 0; // Blue
 
// Packed in little endian: y == 0x31FF65
int y = (b[0] & 0xFF) << 0
 | (b[1] & 0xFF) << 8
 | (b[2] & 0xFF) << 16;
Unpacking the values
 
// Raw int32 as input
int x = 0x31FF65;
 
// Unpacked in big endian: {0x65, 0xFF, 0x31}
byte[] c = {
 (byte)(x >> 16),
 (byte)(x >> 8),
 (byte)(x & 0xFF)
};
 
// Unpacked in little endian: {0x31, 0xFF, 0x65}
byte[] d = {
 (byte)(x & 0xFF),
 (byte)(x >> 8),
 (byte)(x >> 16)
};

Basic Programs