From HackerMonthly-issue15
By Peteris Krumins
I am going to write an article about bit operation skills familiar to embedded system developers. bit operation skills can skillfully and effectively operate integers. when calculating operations such as the number of 1 contained in an integer, these skills can be done with only a few bit operators.
Assume that you have knowledge of 2's complement and bitwise operation.
The following is a short example:
&-And
|-Or
^-Xor
~ -Not
<-Move left
>-Right Shift
The integer in this Article refers to an 8-bit Signed INTEGER (although it is also applicable to any-length signed integer). We use x to represent the result, and y to represent it. each bit of x has b7, b6, b5, b4, b3, b2, b1, and b0. b0 indicates the highest bits and b0 indicates the lowest bits.
I will start with the most commonly used tips, and then gradually become more difficult skills, and use the sample code to explain how each technique works.
Bit operation skill 1: Judge an integer parity
If (x & 1) = 0 ){
X is even
}
Else {
X is odd
}
I believe everyone has seen this. The principle is to judge that the last bit b0 is an odd number if it is 1. use 1 and x to remove b0. If the result is 0 x, it is an even number. Otherwise, x is an odd number.
Let's look at some examples. For example, 43 is an odd number, which is expressed as 00101011 in binary notation. Its last b0 is 1, AND it AND 1 are used for AND operations:
00101011
& 00000001
--------
00000001
We can see that AND erased the b1-b7, but b0 remains unchanged, the final result of the operation is 1, telling us that it is his odd number.
Let's take a look at-43 and remind us that in the 2's complement representation method, the negative step for a positive integer is to reverse each bit and then add 1, therefore, the Binary Expression of-43 is 11010101. again, the last bit is 1, so it is an odd number. (if we use the complement Code of 1, it is incorrect)
Let's look at an even 98. Its binary value is 1100010.
01100010
& 00000001
--------
00000000
AND is 0, which means that the b0 of 98 is 0 AND the specified integer is an even number.
-98: the binary value is 10011110. Similarly, b0 is 0, AND the result is 0.
Bit operation technique 2: Determine whether the nth digit is set to 1.
If (x & (1 <n )){
N-th bit is set
}
Else {
N-th bit is not set
}
In the previous tip, we saw (x & 1) test whether the first digit is set to 1. this technique can further determine whether the nth digit is set to 1. the method is to shift n places to the left AND then find AND. This will erase the other places except the n bit.
The following demonstrates the effect of left shifting.
1 00000001 (equivalent to 1 <0)
1 <1 00000010
1 <2 00000100
1 <3 00001000
1 <4 00010000
1 <5 00100000
1 <6 01000000
1 <7 10000000
Well, we will shift n places to the left AND then AND x AND then erase the other places except the nth place. if the result after "AND" is 0, the bit must be 0; otherwise, it is set to 1.
Let's look at several examples.
If the third digit of 122 has a value, the following operation will find the answer:
122 & (1 <3)
The binary value of 122 indicates 01111010,1 <3 is 00001000.
01111010
& 00001000
--------
00001000
We can see that the final result is not 0, so the third digit of 122 is set to 1.
So is the 5th-33 bits set to 1?
11011111 (-33 in binary)
& 00100000 (1 <5)
--------
00000000
The result is 0, so the 5th bits are not set to 1.
Tip 3 place location n 1
Y = x | (1 <n)
This technique combines the 1 <n and OR operations. The 1 shifted left and the other number OR operations will place that number at the n position 1. because the result of 0 and any bit OR remains unchanged, but the result of 1 and any bit OR is 1.
Suppose a number of 120, we want to place it in the 2nd position 1.
01111000 (120 in binary)
| 00000100 (1 <2)
--------
01111100
Try again-120 6th location 1
10001000 (-120 in binary)
| 01000000 (1 <6)
--------
11001000
Tip 4: place the nth position 0
Y = x &~ (1 <n)
The core part of this method is ~ (1 <n), which returns the position 1 except the nth position.
~ 1 11111110 (same ~ (1 <0 ))
~ (1 <1) 11111101
~ (1 <2) 11111011
~ (1 <3) 11110111
~ (1 <4) 11101111
~ (1 <5) 11011111
~ (1 <6) 10111111
~ (1 <7) 01111111
Whether the nth digit is 0 or 1, the effect of x AND these numbers AND is 0 at the nth position.
Let's take a look at the example below. Set the 127 position to 0.
01111111 (127 in binary)
& 11101111 (~ (1 <4 ))
--------
01101111
Tip 5: reverse the nth Digit
Y = x ^ (1 <n)
This method also uses the technique to set position n to 1, but uses the XOR operation. If they are the same, the result is 0. Otherwise, the result is 1. so how can we switch the nth bit? If the nth digit is 1, and after 1 XOR, 1 becomes 0, and the result of 0 and 1 XOR is 1, the bitwise is reversed.
The following example shows how to reverse the 01110101 5th bits:
01110101
^ 00100000
--------
01010101
What if 5th bits are already 0?
01010101
^ 00100000
--------
01110101
Is there any clue? XOR is restored twice. Clever XOR is often used to calculate RAID array parity and simple encryption functions and other aspects
Tip 6: Set the rightmost 1 to 0.
Y = x & (x-1)
Finally, it's interesting! To be honest, the first five methods are boring.
This method sets the last 1 to 0, for example 001010.10, to 00101000. Or 00010000, to 0.
Example:
01010111 (x)
& 01010110 (x-1)
--------
01010110
01011000 (x)
& 01010111 (x-1)
--------
01010000
10000000 (x =-128)
& 01111111 (x-1 = 127 (overflow ))
--------
00000000
11111111 (x = All are 1)
& 11111110 (x-1)
--------
11111110
00000000 (x is not 1 bit)
& 11111111 (x-1)
--------
00000000
What is its principle?
If you think about it, you will find the following two situations:
1. In the ranking column, 1. Minus 1 will change the low position to 1 AND change the bit of the last 1 to 0. This step AND the original value AND shield the part from the back of the last 1.
2. In the ranking column, No 1 is 0. This is the result of subtracting 1 AND changing all overflow bits to 1. AND is the result of both 0 AND 0.
Tip 7: dial the rightmost 1
Y = x & (-x)
In this method, locate the rightmost 1 and place the other 0, for example, 01010.100, converted to 00000100.
Example:
10111100 (x)
& Amp; 01000100 (-x)
--------
00000100
01110000 (x)
& Amp; 10010000 (-x)
--------
00010000
00000001 (x)
& Amp; 11111111 (-x)
--------
00000001
10000000 (x =-128)
& Amp; 10000000 (-x =-128)
--------
10000000
11111111 (x = all bits one)
& Amp; 00000001 (-x)
--------
00000001
00000000
& Amp; 00000000 (-x)
--------
00000000
This technique is attributed to the 2's complement. In 2's complement,-x and ~ X + 1.
Tip 8: set the first position after 1 on the right to 1
Y = x | (x-1)
It is better to combine the example to understand. 01010000 is changed to 01011111. From the first 1 on the right, the following 0 is changed to 1.
This is not a perfect technique. When x = 0, the result is 1.
Example:
10111100 (x)
| 10111011 (x-1)
--------
10111111
01110111 (x)
| 01110110 (x-1)
--------
01110111
00000001 (x)
| 00000000 (x-1)
--------
00000001
10000000 (x =-128)
| 01111111 (x-1 = 127)
--------
11111111
11111111 (x =-1)
| 11111110 (x-1 =-2)
--------
11111111
00000000 (x)
| 11111111 (x-1)
--------
11111111
Tip 9: dial the first 0 to the rightmost
This technique is the opposite of 7th. Find the rightmost 0, set it to 1, and set other positions to 0. For example, set 10101011. Convert to 00000100.
More examples:
--------
10001000 (~ X)
& 01111000 (x + 1)
--------
00001000
00000001 (x)
--------
11111110 (~ X)
& 00000010 (x + 1)
--------
00000010
10000000 (x =-128)
--------
01111111 (~ X)
& 10000001 (x + 1)
--------
00000001
11111111 (x = no rightmost 0-bit)
--------
00000000 (~ X)
& 00000000 (x + 1)
--------
00000000
00000000 (x)
--------
11111111 (~ X)
& 00000001 (x + 1)
--------
00000001
Tip 10: Set the rightmost 0 position to 1
Y = x | (x + 1)
Set 0 to 1 on the rightmost side. For example, set 10100011 to 10100111.
More examples:
10111100 (x)
| 10111101 (x + 1)
--------
10111101
01110111 (x)
| 01111000 (x + 1)
--------
01111111
00000001 (x)
| 00000010 (x + 1)
--------
00000011
10000000 (x =-128)
| 10000001 (x + 1)
--------
10000001
11111111 (x = no rightmost 0-bit)
| 00000000 (x + 1)
--------
11111111
00000000 (x)
| 00000001 (x + 1)
--------
00000001
Other content:
If you are interested in other bit operations, there are some Python and C code below to print 8-bit signed integers.
Python code:
def int_to_bin(num, bits=8):
r = ''
while bits:
r = ('1' if num&1 else '0') + r
bits = bits - 1
num = num >> 1
print r
C code:
void int_to_bin(int num) {
char str[9] = {0};
int i;
for (i=7; i>=0; i--) {
str[i] = (num&1)?'1':'0';
num >>= 1;
}
printf("%s\n", str);
}