Bit tricks every programmer should know
Vladislav
Posted on June 2, 2022
Intro
Hey everyone, I bet during a regular day at work you guys rarely shift bits left and right, applying ^ (XOR) or & (AND). So today I want to shed some light on a few basic bit tricks that you all might find helpful (or maybe not).
Left Shift
The basic one, but let's refresh our memories here and look at examples of how the left shift <<< operator works.
Example:
Let's say we want to shift number 3 (11 in binary) by one bit to the left and it gives us 6 (110).
3 << 1 = 110 = 6
3 << 2 = 1100 = 12
3 << 3 = 11000 = 24
Code:
fn left_shift(num: usize, offset: usize) -> usize {
num << i
}
Check if the Nth bit is set
This one is a bit trickier, it tells us whether the Nth bit from the right side is set to 1. And we gonna use & (AND) operator to do so.
Example:
Let's say we want to check if 0 or 3rd bits are set to 1 in number 8 (1000 in binary).
8 = 1000
if offset == 0:
1000 & 0001 = 0 -> false (not set)
if offset == 3:
1000 & 1000 = 1 -> true (set)
Code:
fn is_set(num: usize, offset: usize) -> bool {
(num & (1 << offset)) != 0
}
Set Nth bit to 1
Ok, here we're actually going to set a particular bit to 1 in case it's 0, or keep it as 1 if it's already set to 1.
Example:
Let's continue playing with the number 8 (1000 in binary).
(8) 1000 set 3rd and 0th bit (from right) to 1
1000 | 1000 = 1000 == 8 (nothing changed since it was already 1)
1000 | 0001 = 1001 = 9 (set first bit to 1)
Code:
fn set_bit(num: usize, offset: usize) -> usize {
num | (1 << offset)
}
Flip Nth bit
Here we continue playing with one bit at a time. Similar to the previous one, we do not only set the bit to 1 but actually flip the actual value of a bit. For this, we gonna use ^ (XOR)!
Example:
Again 8 is 1000 in binary
1000(8) ^ 1000(8) = 0 (flipped left 1 to 0)
1000 ^ 1001 = 1001 (flipped right 1)
Code:
fn flip_bit(num: usize, offset: usize) -> usize {
num ^ (1 << offset)
}
Number complement (NOT)
This is another standard operator many people don't even know what is it for. ! (NOT) (in java it would be ~) inverts all bits of a particular number.
Example:
Let's take 9 as our integer (1001 in binary)
We can represent 9 as u8, u32, etc, let's consider u32 to resolve confusion.
!1001 = 11111111111111111111111111110110
Because = 1001 in 32-bit representation is actually:
00000000000000000000000000001001, so inverting all bits gives us 11111111111111111111111111110110, which is 4294967286 in decimal.
Code:
fn not(num: u32) -> u32 {
!num
}
Clear Nth bit
This one is pretty straightforward, though the concept is quite interesting. The goal is to set Nth bit to zero.
Example:
Again the integer is going to be 9 (1001).
Then let's say we want to clear the first bit from the right side.
As we already know ! operator (complement) inverts all the bits for us. So we can shift 1 by offset to find the bit we're looking for.
- 1 << offset = 1 in our case (0th bit)
- !1 = 1111111*0* (depending on type, let's keep u8)
- return 1001 & 11111110 = 1000 (8)
Code:
fn clear_bit(num: usize, offset: usize) -> usize {
let mask = !(1 << offset);
num & mask
}
Calculating Hamming weight
Hamming weight is essentially a number of ones in a binary representation of a number. There is an interesting observation has been made by Brian Kernighan,coauthor of first C language Book, which we're going to use here.
Every time we apply n & (n - 1) where n is 32-bit integer, the rightmost bit becomes 0.
Example:
Let's take binary 01010101.
1st iteration: 01010100
2nd iteration: 01010000
3rd iteration: 01000000
So by counting a number of iterations we can calculate the number of ones.
Code:
fn hamming_weight (mut n: usize) -> usize {
let mut count = 0;
while n != 0 {
n &= n - 1;
count += 1;
}
return count;
}
Check if exactly one bit is set
Here is another interesting observation. If our number is a power of 2, then we can say that only one bit is set. To check this, we just need to subtract one and apply & operator!
Example:
8 = 1000
8 - 1 = 7 = 0111
1000 & 0111 = 0000 -> TRUE!
Code:
fn check_exactly_one_bit_is_set(num: usize) -> bool {
num != 0 && (num & (num - 1)) == 0
}
Conclusion
I hope you find those little tricks as fascinating as I think of them and maybe even apply them in your regular job (but don't forget about code readability!).
Posted on June 2, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.