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
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.
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.
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.
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 .
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With