Search code examples
c++cwhile-loopbit-manipulationbitwise-operators

How do you efficiently count the trailing zero bits in a number?


I've written a function trailing_zeroes(int n) that returns the number of the trailing zeroes in the binary representation of a number.

Example: 4 in binary is 100, so the function in this case returns 2.

unsigned trailing_zeroes(int n) {
    unsigned bits;

    bits = 0;
    while (n >= 0 && !(n & 01)) {
        ++bits;
        if (n != 0)
            n >>= 1;
        else
            break;
    }
    return bits;
}

The reason of the if statement is because in case n equals to 0, there will be a loop.

I think it's pretty ugly this code written like this; is there a better way?

I want to avoid the break statement inside the while, because a lot of people told me that using that statement inside while/for sometimes could be "informal". I thought to rewrite the function like this, but I don't think it's the best way to do it:

unsigned bits;
if (n == 0)
    return bits = 1;

bits = 0;
while (!(n & 01)) {
    ++bits;
    n >>= 1;
}

Solution

  • Your function is incorrect: it still has an infinite loop for 0. The test should be:

    while (n > 0 && !(n & 1))
    

    Note that you cannot handle negative numbers with this approach, hence your function should probably take an unsigned number argument, or you could convert the argument to unsigned.

    Your function should special case 0 and use a simpler loop:

    unsigned trailing_zeroes(int n) {
        unsigned bits = 0, x = n;
    
        if (x) {
            while ((x & 1) == 0) {
                ++bits;
                x >>= 1;
            }
        }
        return bits;
    }
    

    The above function is very simple and easy to understand. It is quite fast if the result is small. The value returned for 0 is 0 as in your function, which is questionable as 0 really has as many trailing zeroes as value bits in the unsigned type.

    There is a more efficient approach with a constant number of steps:

    unsigned trailing_zeroes(int n) {
        unsigned bits = 0, x = n;
    
        if (x) {
            /* assuming `x` has 32 bits: lets count the low order 0 bits in batches */
            /* mask the 16 low order bits, add 16 and shift them out if they are all 0 */
            if (!(x & 0x0000FFFF)) { bits += 16; x >>= 16; }
            /* mask the 8 low order bits, add 8 and shift them out if they are all 0 */
            if (!(x & 0x000000FF)) { bits +=  8; x >>=  8; }
            /* mask the 4 low order bits, add 4 and shift them out if they are all 0 */
            if (!(x & 0x0000000F)) { bits +=  4; x >>=  4; }
            /* mask the 2 low order bits, add 2 and shift them out if they are all 0 */
            if (!(x & 0x00000003)) { bits +=  2; x >>=  2; }
            /* mask the low order bit and add 1 if it is 0 */
            bits += (x & 1) ^ 1;
        }
        return bits;
    }
    

    Note that we could handle any larger int size by changing the first step to

    while (!(x & 0x0000FFFF)) { bits += 16; x >>= 16; }
    

    Some compilers have a built-in function __builtin_ctz() to count the number of trailing zeroes using very efficient assembly code. It is not a C Standard function but at the cost of reduced portability, you might want to use it if it is available. Check your compiler's documentation.

    Here is the abstract from GCC documentation:

    Built-in Function: int __builtin_ctz (unsigned int x)

    Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.