How do you store 3 numbers in a single byte using bit shifting in java, ie use the first 3 bits for R, the next 3 bits for G, and the last 2 bits B. I think I know how to retrieve the numbers from the bytes, however an example with encoding and decoding would be great.
Thanks Jake
EDIT:
The range of the values for R and G would be 0-7 and 0-3 for B.
Given r, g and b are in the range 0 - 255:
rgb = (b >>> 6) << 6 | (g >>> 5) << 3 | (r >>> 5);
This is filling out the result in this order:
+--+--+--+--+--+--+--+--+
|B7|B6|G7|G6|G5|R7|R6|R5|
+--+--+--+--+--+--+--+--+
i.e. I've assumed that when you've said "first" you meant least significant. If you want them the other way around it would be:
rgb = (b >>> 6) | (g >>> 5) << 2 | (r >>> 5) << 5;
Related
I have to write a function that does a left circular shift of the bits of y positions.
For example, if I put: 01011000 and 2 as the y, the function has to return 01100001.
I have tried to use Integer.rotateLeft() but it seems to be useless for this.
This should work I think:
int rotate_8bits_left(int val, int y) {
// amend y to the range [0, 7] with this:
// y = ((y % 8) + 8) % 8;
// or better, with this:
y = y & 0x7;
// do the rotation
return ((val << y) & 0xFF) | (val >> (8-y));
}
Let's explain the different parts:
// move val left y bits:
(val << y)
Above however keeps the bits that get beyond the 8th bit, so we need to truncate them, so we go with:
// move val left y bits and truncate anything beyond the 8th bit:
(val << y) & 0xFF
Now we need to add the bits that went out, to the beginning. We can calculate the bit that went out to the left by just moving to the right:
// move to the right, 8-y bits
val >> (8-y)
If we now glue together the two parts, we would get the rotation:
int new_val = ((val << y) & 0xFF) | (val >> (8-y));
Now for the first part, we want to handle y that might not be in the range [0, 8]. We can amend y to this range, before using it, with:
y = ((y % 8) + 8) % 8;
The expression above fixes both negative and positive values of y, if y is negative the modulo would return a negative value in the range [-7, -1], then by adding 8 we get back to the positive range. We have to do modulo again, for the case where y was positive and adding 8 to fix the negative case took it back to be above 8. The second modulo fixes this.
But we can achieve the same amendment for y with a more simple approach, by leaving only the 3 first bits that encounter for the range [0, 7], treating 8 as 0, this can be done with the following expression, that works well for both negative and positive values of y:
y = y & 0x7;
Trying to store three integers into one to use for a hash, and decode back into their original values.
The variables:
x = 3 byte integer (Can be negative)
z = 3 byte integer (Can be negative)
y = 2 byte integer (Cannot be negative)
My current code - doesn't work with negatives:
long combined = (y) | (((long) z) << 16) | ((((long) x)) << 40);
int newX = (int) (combined >> 40); // Trim off 40 bits, leaving the heading 24
int newZ = (int) ((combined << 24) >> (40)); // Trim off 24 bits left, and the 16 bits to the right
int newY = (int) ((combined << 48) >> 48); // Trim off all bits other then the first 16
It doesn't work for negatives because your "3 byte integer" or "2 byte integer" is actually a regular 4-byte int. If the number is negative, all the highest bits will be set to "1"; if you binary-or the numbers together, these high 1 bits will overwrite the bits from the other numbers.
You can use bit-masking to encode the number correctly:
long combined = (y & 0xffff) | (((long) z & 0xffffff) << 16) | ((((long) x & 0xffffff)) << 40);
This will cut off the high-bits outside the 16 or 24 bit range that you're interested in.
The decoding already works fine, because the bit-shifting that you perform takes care of sign-extension.
Java Integer class has the static method highestOneBit method which will return a value with a single one-bit, in the position of the highest-order one-bit in the specified value, or zero if the specified value is itself equal to zero.
For example input of int 17 will return 16; As 17 can be represented in binary as 10001 so it will return the furthest bit left which is equal to 16.
And in Integer class it has the following implementation in Java doc.
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
I just want to know the logic behind implementing it this way and the logic behind using shift operations
. Can any one put some light on it.
This algorithm calculates for a given i whose binary representation is:
0..01XXXXXXX...XXXX
the value
0..011111111...1111
That's what the 5 |= operators do.
Then, in the return statement, it subtracts from it that value shifted right by one bit
0..001111111...1111
to get the result
0..010000000...0000
How does it work:
The highest possible 1 bit the the 32nd (left most) bit. Suppose the input number has 1 in that bit:
1XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
You or that value with the value shifted right by 1 (i >> 1) and get
11XXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
Then you or that new value with the value shifted right by 2 (i >> 2) and get
1111XXXX XXXXXXXX XXXXXXXX XXXXXXXX
Then you or that new value with the value shifted right by 4 (i >> 4) and get
11111111 XXXXXXXX XXXXXXXX XXXXXXXX
Then you or that new value with the value shifted right by 8 (i >> 8) and get
11111111 11111111 XXXXXXXX XXXXXXXX
Finally you or that new value with the value shifted right by 16 (i >> 16) and get
11111111 11111111 11111111 11111111
If the highest 1 bit is smaller than the 32nd bit, these operations still turn all the bits to the right of it to 1 and keep the remaining (higher bits) 0.
The i |= statements help to compute a sequence of ones that is the same length as i. For example, for 101011 it computes 111111. I've explained how it works in this answer (I can't retype it right now since I am on mobile).
So basically, once you have the string of ones, subtracting itself shifted right one bit gives the H.O. bit.
111111 - (111111 >>> 1) = 111111 - 011111 = 100000
The first five lines (i |= (i >> x)) will set every bit below the highest 1-bit to 1. Then, the final line will subtract every 1-bit below the highest one, so that only the highest 1-bit will remain.
For simplicity, let's pretend an int was 8 bits. The code would in that case be like this:
public static int highestOneBit(int i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
return i - (i >>> 1);
}
Now, let's say we have the value 128 (10000000). This is what would happen:
// i == 10000000
i |= (i >> 1); // i = 10000000 | 11000000 = 11000000
i |= (i >> 2); // i = 11000000 | 11110000 = 11110000
i |= (i >> 4); // i = 11110000 | 11111111 = 11111111
return i - (i >>> 1); // 11111111 - 01111111 = 10000000
The >> is an arithmetic right shift, so it will preserve the signed bit.
The last >>> is a logical right shift, which will not preserve the signed bit. It will always insert zeroes on the left side.
Now, let's try with 64 (01000000):
// i == 01000000
i |= (i >> 1); // i = 01000000 | 00100000 = 01100000
i |= (i >> 2); // i = 01100000 | 00011000 = 01111000
i |= (i >> 4); // i = 01111000 | 00000111 = 01111111
return i - (i >>> 1); // 01111111 - 00111111 = 01000000
What is the difference between:
int n = (b1 & 0xff) << 24 | (b2 & 0xff) << 16 | (b3 & 0xff) << 8 | b4 & 0xff
and
int n = b1 << 24 | b2 << 16 | b3 << 8 | b4
? Why should we AND each byte with 255?
First you need to understand that b1 <<< 24 expects the a operand to be of type int or long. So, if b1 is a byte, Java will convert it to an int before the shift takes place.
That conversion happens by mapping each byte value into the corresponding int value. The problem is that byte is a signed type, which means that the possible values are -128 through to +127. Therefore, when you convert a byte with a negative value, you will get an int with a negative value; e.g. the byte 11111111 (binary) which is -1 becomes 11111111111111111111111111111111 (binary) which is also -1.
Those leading ones are the result of sign extension, and we do NOT want them if we are about to shift them and combine them in a bitwise fashion.
Hence, you will often see a byte being masked with 0xff to remove the (unwanted) results of sign extension after the conversion. For example
11111111111111111111111111101110 &
00000000000000000000000011111111
gives
00000000000000000000000011101110
Let me assume types of b1, b2, b3 and b4 are byte.
In this case, their values will be sign extended and if they are negative, the result will be wrong if AND isn't used.
Demo:
class Test {
public static void main(String[] args) {
byte a = (byte)128;
int x1 = a << 8;
int x2 = (a & 0xff) << 8;
System.out.println(x1);
System.out.println(x2);
}
}
Output:
-32768
32768
So I've got 3 ints, 2 of them are only from 0 to 15 (x and z) and 1 (y) goes from 0 to 255. I've been trying to use bit shift with something like this
compressed = (short) (x>>12|y>>8|z);
but it only gets the z value?
Whats the proper way to do this
You need to use the shifts in the other direction, use brackets as shift has low precedence.
compressed = (short) ((x << 12) | (y << 8) | z);
You are shifting the wrong direction:
compressed = (short) ((x<<12) | (y<<4) | z);