Skip to content
nbyinfinity
Go back

๐Ÿ”ข Bitcount in C: Counting Set Bits Efficiently

โ€ข 4 min read โ€ข ~660 words
๐Ÿ”ข Bitcount in C: Counting Set Bits Efficiently

Table of contents

Open Table of contents

๐Ÿ“– Introduction

In this blog post, we explore how to count the number of set bits (1s) in an integer in C based on the method described by K&R (The C Programming Language by Brian Kernighan and Dennis Ritchie). We will compare two approaches:

  1. A simple method that shifts and checks each bit sequentially.
  2. A faster method using K&Rโ€™s bitwise trick x & (x - 1).

๐Ÿšถ 1. The Simple Method: Bit-by-Bit Shift

This approach is straightforward: it inspects each bit one by one starting from the least significant bit (LSB - rightmost bit) and shifts the number to the right until all bits are processed.

Algorithm Steps

Implementation

int bitcount_simple(unsigned int i) {
    int count = 0;

    for (; i != 0; i >>= 1) {
        if (i & 01) {
            count++;
        }
    }
    return count;
}

Time Complexity: Proportional to the position of the most significant (Leftmost) 1-bit (O(total bits)) in the worst case.


โšก 2. The Faster Method: K&Rโ€™s Bitwise Trick

Instead of shifting through every bit position, we can use a clever bitwise trick that clears the rightmost set bit (1) in each iteration:

x = x & (x - 1);

๐Ÿ” Why Does x & (x - 1) work?

In binary twoโ€™s complement arithmetic, subtracting 1 from x (x - 1):

When we perform x & (x - 1):

Hence, each operation x & (x - 1) clears exactly one set bitโ€”the lowest-order 1.

๐Ÿ“Š Step-by-Step Example

Letโ€™s trace x = 196:

  x             = 196   ->  11000100  (binary)
  -1            = 255   ->  11111111  (binary) // two's complement representation of -1
  -----------------------------------------
  x + (-1)      = 195   ->  11000011  (binary)
    // rightmost 1 bit (3rd bit from the right)
    // all bits after the rightmost 1 bit (2nd and 1st bits from the right) become 1s
    // all bits before the rightmost 1 bit (4th, 5th, 6th, and 7th bits from the right) remain unchanged
  -----------------------------------------

  
  x              = 196  ->  11000100  (binary)
  x - 1          = 195  ->  11000011  (binary) // as explained above
  --------------------------------------------
  x & (x-1)      = 192  ->  11000000  (rightmost 1-bit - 3rd bit from the right cleared!)
  --------------------------------------------

๐Ÿ’ป Implementation

By repeating this trick until x becomes 0, the loop executes only as many times as there are 1s:

int bitcount_faster(unsigned int x) {
    int count = 0;

    while(x != 0){
        x = x & (x - 1);
        count++;
    }
    return count;
}

โš–๏ธ Performance Comparison

MetricSimple Shift MethodKernighanโ€™s Method
IterationsEqual to total bits up to the Most Significant Bit (MSB)Equal only to the number of set bits (1s)
Best CaseO(1) when x == 0O(1) when x == 0
Worst CaseO(total bits up to the (MSB)) (e.g., 32 or 64 steps)O(number of 1s)

๐Ÿ Conclusion

K&Rโ€™s algorithm x & (x - 1) is an elegant bitwise technique that skips zero-bits entirely. It reduces execution time, making it the preferred method for counting set bits.


Share this post:

Next Post
๐Ÿ› ๏ธ Makefile Cheatsheet