TIL: x &= (x - 1) deletes the rightmost 1 bit in x

published

last modified

systems
linux

2kb

Why does this happen? The a-ha moment is to see what happens when we add 11 to x1x - 1 which equals xx. Say we have the number 1010 in decimal as our x1x - 1, and add one to it, this would look like:

1010 + 
0001 
adding 1 to 10

The result would be (11 = x):

1011
the result, 11

The astute observer would notice that in x1x - 1 there is a zero at the first one bit in xx. This is because, what adding 11 to x1x - 1 will do is place a 11 bit into the first open position (the first 0). This means that first zero in x1x - 1 will correspond to the first 1 bit in xx. So if we bitwise & this with the original number this will drop that bit (the rightmost 1 bit) in xx.

1010 &
1011
----
1010
the revelation, deleting the rightmost bit

Why Does This Even Matter?

Well, with this interesting fact counting bits in an integer becomes slighly faster than just right shifting the integer and checking if the bitwise & of 1 and x is equal to 1. The primitive countbits may look like this:

count_bits_primitive.c
int o_countbits(unsigned x) {
    int count = 0;
    for (; x != 0; x >>= 1) {
        if ((x & 1) == 1) {
            ++count;
        }
    }
    return count;
}

Which will have to right shift for every position in x. But with our new found knowledge we can re-write this as:

count_bits_fast.c
int n_countbits(unsigned x) {
    int count = 0;
    // deletes the right most 1 bit every iteration
    for (; x != 0; x &= (x - 1)) {
        ++count;
    }
    return count;
}

This way we don't have to count any of the zeroes in the integer. Awesome! +1 for micro optimisations.

Contact

If you have any comments or thoughts you can reach me at any of the places below.