Low level bit manipulation has never been my strong point. I will appreciate some help in understanding the following use case of bitwise operators.Consider...
int age, gender, height, packed_info;
. . . // Assign values
// Pack as AAAAAAA G HHHHHHH using shifts and "or"
packed_info = (age << 8) | (gender << 7) | height;
// Unpack with shifts and masking using "and"
height = packed_info & 0x7F; // This constant is binary ...01111111
gender = (packed_info >> 7) & 1;
age = (packed_info >> 8);
I am not sure what this code is accomplishing and how? Why use the magic number 0x7F ? How is the packing and unpacking accomplished?
The left shift operator means "multiply by two, this many times". In binary, multiplying a number by two is the same as adding a zero to the right side.
The right shift operator is the reverse of the left shift operator.
The pipe operator is "or", meaning overlay two binary numbers on top of each other, and where there is a 1 in either number the result in that column is a 1.
So, let's extract the operation for packed_info:
And the unpacking is the reverse.
A more condense answer:
AAAAAAA G HHHHHHH
Packing:
Alternatively you can just sum components if ie when used in MySQL SUM aggregate function
Unpacking:
Another (longer) example:
Say you have an IP address you want to pack, however it is a fictional IP address eg 132.513.151.319. Note that some components greater then 256 which requires more then 8 bits unlike real ip addresses.
First we need to figure out what offset we need to use to be able to store the max number. Lets say with our fictional IPs no component can be bigger then 999 that means we need 10 bits of storage per component (allows numbers up to 1014).
Which gives
dec 342682502276
orbin 100111111001001011110000000010010000100
Now lets unpack the value
Where
(1 << 10) - 1
is a binary mask we use to hide bits on the left beyond the 10 right most bits we are interested in.Same example using MySQL query
If you were going to store a date as a number, maybe you would accomplish it by multiplying the year by 10000, the month by 100 and adding the day. A date such as July, 2, 2011 would be encoded as the number 20110702:
We can say that we encoded the date in a yyyymmdd mask. We could describe this operation as
This is the same thing that is happenning with the age, gender and height encoding, only that the author is thinking in binary.
See the ranges that those values may have:
If we translate those values to binary, we would have this:
With this in mind, we can encode the age-gender-height data with the mask aaaaaaaghhhhhhh, only that here we are talking about binary digits, not decimal digits.
So,
In binary, the Shift-Left operator (<<) moves a value n positions to the left. The "Or" operator ("|" in many languages) combines values together. Therefore:
Now, how to "decode" those values?
It's easier in binary than in decimal:
The Shift-Right operator (>>) moves a value n positions to the right (whatever digits shifted "out" of the rightmost position are lost). The "And" binary operator ("&" in many languages) masks bits. To do that it needs a mask, indicating which bits to preserve and which bits to destroy (1 bits are preserved). Therefore:
Since 1111111b in hex is 0x7f in most languages, that's the reason for that magic number. You would have the same effect by using 127 (which is 1111111b in decimal).
You can see the expression
x & mask
as an operation that removes fromx
the bits that are not present (i.e., have value 0) inmask
. That means,packed_info & 0x7F
removes frompacked_info
all the bits that are above the seventh bit.Example: if
packed_info
is1110010100101010
in binary, thenpacked_info & 0x7f
will beSo, in
height
we get the lower 7 bits ofpacked_info
.Next, we are shifting the whole
packed_info
by 7, this way we remove the information which we have already read out. So we get (for the value from previous example)111001010
The gender is stored at the next bit, so with the same trick:& 1
we are extracting only that bit from the information. The rest of the information is contained at offset 8.Packing back is not complicated, too: you take
age
, shift it 8 bits (so you get1110010100000000
from11100101
), shift thegender
by 7 (so you get00000000
), and take the height (assuming it would fit lower 7 bits). Then, you are composing all of them together:Same requirement I have faced many times. It is very easy with the help of Bitwise AND operator. Just qualify your values with increasing powers of two(2). To store multiple values, ADD their relative number ( power of 2 ) and get the SUM. This SUM will consolidate your selected values. HOW ?
Just do Bitwise AND with every value and it will give zero (0) for values which were not selected and non-zero for which are selected.
Here is the explanation:
1) Values ( YES, NO, MAYBE )
2) Assignment to power of two(2)
3) I choose YES and MAYBE hence SUM:
This value will store both YES as well as MAYBE. HOW?
Hence SUM consists of
For more detailed explanation and implementation visit my blog
As the comment says, we're going to pack the age, gender and height into 15 bits, of the format:
Let's start with this part:
To start with, age has this format:
where each A can be 0 or 1.
<< 8
moves the bits 8 places to the left, and fills in the gaps with zeroes. So you get:Similarly:
Now we want to combine these into one variable. The
|
operator works by looking at each bit, and returning 1 if the bit is 1 in either of the inputs. So:If a bit is 0 in one input, then you get the bit from the other input. Looking at
(age << 8)
,(gender << 7)
andheight
, you'll see that, if a bit is 1 for one of these, it's 0 for the others. So:Now we want to unpack the bits. Let's start with the height. We want to get the last 7 bits, and ignore the first 8. To do this, we use the
&
operator, which returns 1 only if both of the input bits are 1. So:So:
To get the age, we can just push everything 8 places to the right, and we're left with
0000000AAAAAAAA
. Soage = (packed_info >> 8)
.Finally, to get the gender, we push everything 7 places to the right to get rid of the height. We then only care about the last bit: