Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use of the bitwise operators to pack multiple values in one int

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?

Source

like image 275
maxpayne Avatar asked Jul 02 '11 12:07

maxpayne


People also ask

What is bitwise operators used for?

Examples of uses of bitwise operations include encryption, compression, graphics, communications over ports/sockets, embedded systems programming and finite state machines. A bitwise operator works with the binary representation of a number rather than that number's value.

What does bitwise and do to integers?

The & (bitwise AND) in C or C++ takes two numbers as operands and does AND on every bit of two numbers. The result of AND is 1 only if both bits are 1. The | (bitwise OR) in C or C++ takes two numbers as operands and does OR on every bit of two numbers. The result of OR is 1 if any of the two bits is 1.

What is the use of bitwise operator in Python?

Python bitwise operators are used to perform bitwise calculations on integers. The integers are converted into binary format and then operations are performed bit by bit, hence the name bitwise operators. Python bitwise operators work on integers only and the final output is returned in the decimal format.

What are the advantages of using bitwise operations?

Bitwise operations are incredibly simple and thus usually faster than arithmetic operations. For example to get the green portion of an rgb value, the arithmetic approach is (rgb / 256) % 256 . With bitwise operations you would do something as (rgb >> 8) & 0xFF .


2 Answers

As the comment says, we're going to pack the age, gender and height into 15 bits, of the format:

AAAAAAAGHHHHHHH 

Let's start with this part:

(age << 8) 

To start with, age has this format:

age           = 00000000AAAAAAA 

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:

(age << 8)    = AAAAAAA00000000 

Similarly:

gender        = 00000000000000G (gender << 7) = 0000000G0000000 height        = 00000000HHHHHHH 

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:

0011 | 0101 = 0111 

If a bit is 0 in one input, then you get the bit from the other input. Looking at (age << 8), (gender << 7) and height, you'll see that, if a bit is 1 for one of these, it's 0 for the others. So:

packed_info = (age << 8) | (gender << 7) | height = AAAAAAAGHHHHHHH 

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:

0011 & 0101 = 0001 

So:

packed_info          = AAAAAAAGHHHHHHH 0x7F                 = 000000001111111 (packed_info & 0x7F) = 00000000HHHHHHH = height 

To get the age, we can just push everything 8 places to the right, and we're left with 0000000AAAAAAAA. So age = (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:

packed_info            = AAAAAAAGHHHHHHH (packed_info >> 7)     = 0000000AAAAAAAG 1                      = 000000000000001 (packed_info >> 7) & 1 = 00000000000000G 
like image 86
thomson_matt Avatar answered Oct 03 '22 04:10

thomson_matt


This could be a rather long lesson in bit manipulation but first let me point you too the bit masking article on Wikipedia.

packed_info = (age << 8) | (gender << 7) | height; 

Take age and move it's value over 8 bits then take gender and move it over 7 bits and height will occupy the last bits.

age    = 0b101 gender = 0b1 height = 0b1100 packed_info = 0b10100000000             | 0b00010000000             | 0b00000001100 /* which is */ packed_info = 0b10110001100 

Unpacking does the reverse but uses masks like 0x7F (which is 0b 01111111) to trim out the other values in the field.

gender = (packed_info >> 7) & 1; 

Would work like...

gender = 0b1011 /* shifted 7 here but still has age on the other side */        & 0b0001 /* which is */ gender = 0b1 

Note that ANDing anything to 1 is the same as "keeping" that bit and ANDing with 0 is the same as "ignoring" that bit.

like image 41
Andrew White Avatar answered Oct 03 '22 04:10

Andrew White