Handy Bit Manipulation Tricks

Subscribe for New Posts


As a developer, understanding bit manipulation can be extremely powerful when solving certain types of problems. Here are some common bit manipulation tricks that are worth keeping in your toolbox.

Basic Bit Operations

Let’s start with the fundamental bit manipulation operations:

Setting a Bit

To set the bit at position pos in the number n, we use the bitwise OR operator (|) with the left-shifted 1 (i.e., 1 << pos):

function setBit(n: number, pos: number): number {
  return n | (1 << pos);
}

For example, setting the bit at position 2 in the binary number 0b1010 results in 0b1110:

   0b1010
 | 0b0100
-----------
   0b1110

Clearing a Bit

To clear the bit at position pos in the number n, we use the bitwise AND (&) operator with the inverse of the left-shifted 1 (i.e., ~(1 << pos)):

function clearBit(n: number, pos: number): number {
  return n & ~(1 << pos);
}

For example, clearing the bit at position 1 in the binary number 0b1110 results in 0b1010:

   0b1110
 & 0b1101
-----------
   0b1010

Toggling a Bit

To toggle the bit at position pos in the number n, we use the bitwise XOR (^) operator with the left-shifted 1 (i.e., 1 << pos):

function toggleBit(n: number, pos: number): number {
  return n ^ (1 << pos);
}

For example, toggling the bit at position 2 in the binary number 0b1010 results in 0b1110:

   0b1010
 ^ 0b0100
-----------
   0b1110

Checking a Bit

To check if the bit at position pos in the number n is set, we use the bitwise AND (&) operator with 1 after right-shifting n by pos bits:

function checkBit(n: number, pos: number): boolean {
  return (n >> pos) & 1;
}

For example, checking the bit at position 1 in the binary number 0b1110 results in true:

   0b1110
 >>     1
-----------
   0b0001
 & 0b0001
-----------
   0b0001 (true)

Bit Manipulation Tricks

Now, let’s dive into some more advanced bit manipulation tricks:

Checking if a Number is a Power of 2

To check if a number n is a power of 2, we can use the following trick:

function isPowerOfTwo(n: number): boolean {
  return n > 0 && (n & (n - 1)) == 0;
}

The idea is that a number is a power of 2 if and only if it has exactly one bit set. Subtracting 1 from the number will clear the rightmost set bit, and the result of n & (n - 1) will be 0 if and only if n was a power of 2.

Here’s a visual representation:

n = 8 (0b1000)
n - 1 = 7 (0b0111)
n & (n - 1) = 0b1000 & 0b0111 = 0b0000

Counting the Number of Set Bits (Brian Kernighan’s Algorithm)

To count the number of set bits in the binary representation of a number n, we can use the following algorithm:

function countSetBits(n: number): number {
  let count = 0;

  while (n) {
    n = n & (n - 1);

    count++;
  }

  return count;
}

The idea is to repeatedly clear the rightmost set bit of the number until the number becomes 0. Each time we clear a bit, we increment the count.

Here’s a visual representation:

n = 0b1011
n - 1 = 0b1010
n & (n - 1) = 0b1011 & 0b1010 = 0b1010
count = 1

n = 0b1010
n - 1 = 0b1001
n & (n - 1) = 0b1010 & 0b1001 = 0b1000
count = 2

n = 0b1000
n - 1 = 0b0111
n & (n - 1) = 0b1000 & 0b0111 = 0b0000
count = 3

Finding the Rightmost Set Bit

To find the rightmost set bit in a number n, we can use the following trick:

function rightmostSetBit(n: number): number {
  return n & -n;
}

The idea is that -n is the two’s complement of n, which has all the bits set except the rightmost set bit in n. By performing the bitwise AND (&) operation, we get the rightmost set bit.

Here’s a visual representation:

n = 0b1010
-n = 0b0110
n & -n = 0b1010 & 0b0110 = 0b0010

Finding the Rightmost Different Bit of Two Numbers

To find the rightmost different bit between two numbers m and n, we can use the following trick:

function rightmostDifferentBit(m: number, n: number): number {
  return rightmostSetBit(m ^ n);
}

The idea is to first find the bitwise XOR (^) of m and n, which will set the bits that are different between the two numbers. Then, we can use the “Finding the Rightmost Set Bit” trick to get the rightmost different bit.

Here’s a visual representation:

m = 0b1010
n = 0b1100
m ^ n = 0b0110
rightmostSetBit(0b0110) = 0b0010