sof - 2 years ago 82
Java Question

# Bits retrieval of a number

Tried to retrieve some bits of a number, e.g. the marked bits 00001

`01`
1 of the byte 11 below,

``````(byte) 11 >> 1 << 6 >> 5
``````

but why is the result 10 instead of 2 ?

@EDIT

To make a method below, the solution from @Yassin Hajaj seems more feasible.

``````public byte getBits(byte b, int from, int to) { // from & to inclusive

return (byte) (b >> from << (8 - (to - from + 1))) >> (8 - to - 1);
}

getBits((byte) 11, 1, 2); // => 2
``````

Or more universal with the hints from @Andreas,

``````public <T extends Number> long getBits(T n, int from, int to) {

return n.longValue() >>> from << (64 - (to - from + 1)) >>> (64 - to - 1);
}

getBits((byte) 11, 1, 2); // => 2
``````

TL;DR Use `b & 6`, e.g. `(byte)(11 & 6)`. See working `getBits()` implementation(s) at the end.

First of all, casting `11` to a `byte` is rather meaningless, because the `>>` operator will coerce it right back to an `int` value.

To show you why your code doesn't work, here is a program that displays all the intermediate steps:

``````public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
int i1 = i >> 1;
int i2 = i1 << 6;
int i3 = i2 >> 5;
System.out.printf("%3d %s -> %3d %s -> %3d %10s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(int value) {
String s = Integer.toBinaryString(value);
return "0000000".substring(Math.min(7, s.length() - 1)) + s;
}
``````

Output:

``````  0 00000000 ->   0 00000000 ->   0   00000000 ->   0 00000000
1 00000001 ->   0 00000000 ->   0   00000000 ->   0 00000000
2 00000010 ->   1 00000001 ->  64   01000000 ->   2 00000010
3 00000011 ->   1 00000001 ->  64   01000000 ->   2 00000010
4 00000100 ->   2 00000010 -> 128   10000000 ->   4 00000100
5 00000101 ->   2 00000010 -> 128   10000000 ->   4 00000100
6 00000110 ->   3 00000011 -> 192   11000000 ->   6 00000110
7 00000111 ->   3 00000011 -> 192   11000000 ->   6 00000110
8 00001000 ->   4 00000100 -> 256  100000000 ->   8 00001000
9 00001001 ->   4 00000100 -> 256  100000000 ->   8 00001000
10 00001010 ->   5 00000101 -> 320  101000000 ->  10 00001010
11 00001011 ->   5 00000101 -> 320  101000000 ->  10 00001010
12 00001100 ->   6 00000110 -> 384  110000000 ->  12 00001100
13 00001101 ->   6 00000110 -> 384  110000000 ->  12 00001100
14 00001110 ->   7 00000111 -> 448  111000000 ->  14 00001110
15 00001111 ->   7 00000111 -> 448  111000000 ->  14 00001110
16 00010000 ->   8 00001000 -> 512 1000000000 ->  16 00010000
``````

Your upper bits are not getting cleared, because it's operating on `int` values. If you change everything to `byte`, you get:

``````public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
byte i1 = (byte)(i >> 1);
byte i2 = (byte)(i1 << 6);
byte i3 = (byte)(i2 >> 5);
System.out.printf("%3d %s -> %3d %s -> %4d %s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(byte value) {
String s = Integer.toBinaryString(value & 0xFF);
return "0000000".substring(s.length() - 1) + s;
}
``````
``````  0 00000000 ->   0 00000000 ->    0 00000000 ->   0 00000000
1 00000001 ->   0 00000000 ->    0 00000000 ->   0 00000000
2 00000010 ->   1 00000001 ->   64 01000000 ->   2 00000010
3 00000011 ->   1 00000001 ->   64 01000000 ->   2 00000010
4 00000100 ->   2 00000010 -> -128 10000000 ->  -4 11111100
5 00000101 ->   2 00000010 -> -128 10000000 ->  -4 11111100
6 00000110 ->   3 00000011 ->  -64 11000000 ->  -2 11111110
7 00000111 ->   3 00000011 ->  -64 11000000 ->  -2 11111110
8 00001000 ->   4 00000100 ->    0 00000000 ->   0 00000000
9 00001001 ->   4 00000100 ->    0 00000000 ->   0 00000000
10 00001010 ->   5 00000101 ->   64 01000000 ->   2 00000010
11 00001011 ->   5 00000101 ->   64 01000000 ->   2 00000010
12 00001100 ->   6 00000110 -> -128 10000000 ->  -4 11111100
13 00001101 ->   6 00000110 -> -128 10000000 ->  -4 11111100
14 00001110 ->   7 00000111 ->  -64 11000000 ->  -2 11111110
15 00001111 ->   7 00000111 ->  -64 11000000 ->  -2 11111110
16 00010000 ->   8 00001000 ->    0 00000000 ->   0 00000000
``````

Here, the problem is the sign-extension you get from `>>`. Even switching to `>>>` won't work, because the `>>>` still coerces to `int` with sign-extension before the shift happens.

To get rid of sign-extension, you have to convert `byte` to `int` using `b & 0xFF`, because the `&` will coerce `b` to an `int` with sign-extension, then the bitwise AND operator will remove all those bits.

Of course, if you're going to use bitwise AND anyway, just use it to get the desired result, i.e. `b & 0b00000110` (or `b & 6`).

For the same reason as described above, the `getBits()` method doesn't work.

Solution is to still use a bitwise AND operator, but construct the bit-mask from the supplied `from` and `to` values.

The trick here is the use `(1 << x) - 1` to create a mask of `x` bits, e.g. `5` -> `0b00011111`. So if you want from 2 to 4 inclusive, build `0x00011111` (5! bits) and `0x00000011` (2 bits), then XOR them to get `0x00011100`.

``````public static byte getBits(byte b, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
}
``````
``````  0 00000000 ->   0 00000000
1 00000001 ->   0 00000000
2 00000010 ->   2 00000010
3 00000011 ->   2 00000010
4 00000100 ->   4 00000100
5 00000101 ->   4 00000100
6 00000110 ->   6 00000110
7 00000111 ->   6 00000110
8 00001000 ->   0 00000000
9 00001001 ->   0 00000000
10 00001010 ->   2 00000010
11 00001011 ->   2 00000010
12 00001100 ->   4 00000100
13 00001101 ->   4 00000100
14 00001110 ->   6 00000110
15 00001111 ->   6 00000110
16 00010000 ->   0 00000000
``````

For other primitive types, overload the method:

``````public static byte getBits(byte value, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
}
public static short getBits(short value, int from, int to) {
if (from < 0 || from > to || to > 15)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
}
public static int getBits(int value, int from, int to) {
if (from < 0 || from > to || to > 31)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);