Every now and then, you may want to collapse multiple values into a long
, to use as a key for a Map
, for example.
The following code is an example of collapsing three int
s into one long
. Obvious care should be taken here: three int
s don’t actually fit into one long
, so the excess bits are just discarded. If we do this, we can afford to use the lowest 20 bits, plus the sign bit, leaving us with a data range of 1,048,576 to -1,048,575.
For each int
we take the lower 20 bits:
input & 0xfffff
…and the sign bit, which we move to position 21:
(input & Integer.MIN_VALUE) >>> 11
and then combine the two:
(input & 0xfffff | (input & Integer.MIN_VALUE) >>> 11)
Now, we repeat the process for all our inputs and put them in our long
, shifting two of them by 21 and 42 respectively so they don’t overlap:
long l = 0; l |= (long)(input1 & 0xfffff | (input1 & Integer.MIN_VALUE) >>> 11); l |= (long)(input2 & 0xfffff | (input2 & Integer.MIN_VALUE) >>> 11) << 21; l |= (long)(input3 & 0xfffff | (input3 & Integer.MIN_VALUE) >>> 11) << 42;
If you were to combined a higher amount of things with less bits, this loop version will probably be more concise, courtesy of Maldivia:
public static long pack(int i1, int i2, int i3) { int[] data = new int[] { i1, i2, i3 }; long l = 0; for (int i = 0; i < 3; i++) { l |= (long)(data[i] & 0xfffff | (data[i] & Integer.MIN_VALUE) >>> 11) << (i * 21); } return l; }
And to unpack the long
back into pieces:
public static int[] unpack(long l) { int[] res = new int[3]; for (int i = 0; i < 3; i++) { res[i] = (int) (l & 0xfffff); if ((l & 0x100000) != 0) { res[i] |= 0xfff00000; } l >>>= 21; } return res; }