# Trailing Zeros - C

3

I need a program that returns the number of trailing zeros in the binary rapresentation of a number. I found online a function written in C but I don't understand how it works

This is the function:

``````unsigned tzr(unsigned x)
{
unsigned n; /* number of bits */

n = 0;
if (!(x & 0x0000FFFF)) { n += 16; x >>= 16; }
if (!(x & 0x000000FF)) { n +=  8; x >>=  8; }
if (!(x & 0x0000000F)) { n +=  4; x >>=  4; }
if (!(x & 0x00000003)) { n +=  2; x >>=  2; }

n += (x & 1) ^ 1; // anyway what does this do ?

return n;
}
``````

Now I've really tried to understand how this works but I don't get it. I really need someone who could explain it to me, I find this code very complicated.

`0x0000FFFF` = 65535
`0x000000FF` = 255
`0x0000000F` = 15
`0x00000003` = 3

Now, why the program uses those values and makes a bitwise AND with the number?

Then I know that if you want to handle big numbers you must
use a `while` instead of the first `if` statement, like this:

```while (!(x & 0x0000FFFF)) { bits += 16; x >>= 16; } // why should I need this ? ```

But I don't know why ! What's the difference about using a `while` instead of an `if` in this case?

c
bitwise-operators
trailing

1

The hexadecimal constants are AND'ed with the value to check whether the last [number] of digits is zero.`0x0000FFFF` is a number with 16 ones in binary. If the value AND'ed with `0x0000FFFF` is equal to 0, you know that the last 16 digits are zeroes (the `if`s check for the reverse of that statement). Going further `0x000000FF` is a number with 8 ones in binary. The next check is for the last 8 digits, next for 4 digits and the last one for 2 digits as `0x00000003` is `11` in binary. After the checks the numbers are shifted to check whether further digits are also zero. This way we can check for any number of trailing zeroes as the values are powers of 2 and adding them works exactly like working with binary.

Last statement checks for the last digit after all the previous shifting is done - AND with 1 and checking if it's 0 or 1 with a XOR(`^`).

This program checks numbers with 32 bits. You can change the first `if` to a `while` to check larger, e.g. 64-bit, numbers. Another way is to check with `0xFFFFFFFF` and then shift 32 bits at once.

0

The line `n += (x & 1) ^ 1` checks the least significant bit (LSB) of the current state of x. If the LSB is a 1 then (x & 1) yeilds 1 which is then XORed (the caret symbol '^' means to XOR two values) with 1 to give 0 (1 ^ 1 == 0). When x has a 0 in the LSB and is XORed with 1 it yeilds 1 (0 ^ 1 == 1).

0

`!(x&0x0000FFFF)` will be true only when the last 16 bits of `x` are all 0's. The `&` is a bitwise and, and `0x0000FFFFF` is the number ending in 16 1's. So the result of the and is 0 iff all 16 trailing bits are 0 (and so FALSE and `1` reverses the truth value) because if there is at least one 1 among the last 16, the and with the corresponding 1 in the constant will be 1. So then the and is not 0 (so TRUE and `!` reverses the truth value).

So the code says: if the last 16 bits are 1, add 16 to n and throw the last 16 bits away (that is what `x >>= 16` does).
The next line says in a similar way: if the last 8 bits of the (possibly shortened `x`) are 0 ,add 8 to n and throw the rightmost 8 bits away, and so on for 4 and 2 bits as well

The last line adds 1 if the rightmost bit (`x&1`) is 0, otherwise 0 (`1^1 = 0`).

So say if the righmost 15 bits are 0, the first `if` will be false , n remains 0.
The second will be true, as we have more than 8. Tne new x will have 7 0-bits, and n=8.
The third will also be true (we have still 4 or more), so the new x has 3 0-bits after the shift and n=12.
The fourth will also be true (2 or more 0's) so the new x has 1 0-bit and n=14.
The final statement adds 1, so get n=15.

Because we use decreasing powers of 2 we don't need a loop. We get all possible n values this way (except 32, for input `x=0`, a fully correct function should maybe check for that and early abort.

0

`n += (x & 1) ^ 1; // anyway what does this do ?`

This checks the right-most bit. Either it is set or NOT set.

If it is set, then there is NOT another 0 to add onto the running total of trailing zeros, so n+=0.

If it is NOT set, then there is another 0 to add onto the running total of trailing zeros, so n+=1.

Also, your example does NOT compile, it is missing two ; as follows:

``````unsigned tzr(unsigned x)
{
unsigned n; /* number of bits */

n = 0;
if (!(x & 0x0000FFFF)) { n += 16; x >>= 16; }
if (!(x & 0x000000FF)) { n += 8; x >>= 8; }
if (!(x & 0x0000000F)) { n += 4; x >>= 4 } // won't compile due to missing ;
if (!(x & 0x00000003)) { n += 2; x >>= 2 } // won't compile due to missing ;

n += (x & 1) ^ 1; // anyway what does this do ?

return n;
}
``````

Also, you can always try printing out data, for example, every power of 2 has multiple trailing zeros, but only odd amounts of trailing zeros are incremented by an additional 1 from `n += (x & 1) ^ 1;`...

``````cout << tzr(9) << endl << endl; // 1001 (not a power of two )
cout << tzr(8) << endl << endl; // 1000 (8>>2 & 1)^1==1
cout << tzr(4) << endl << endl; // 0100 (4>>2 & 1)^1==0
cout << tzr(2) << endl << endl; // 0010 (   2 & 1)^1==1
cout << tzr(1) << endl << endl; // 0001 (   1 & 1)^1==0
``````

tzr(9) == 0 ==> 0 + (9 & 1) ^ 1 == 0 + 0

tzr(8) == 3 ==> 2 + (8>>2 & 1) ^ 1 == 2 + 1

tzr(4) == 2 ==> 2 + (4>>2 & 1) ^ 1 == 2 + 0

tzr(2) == 1 ==> 0 + (2 & 1) ^ 1 == 0 + 1

tzr(1) == 0 ==> 0 + (1 & 1) ^ 1 == 0 + 0

Program ended with exit code: 0

0

You say, "I need a program that returns the number of trailing zeros in the binary rapresentation of a number." But does it have to be the program you found? Here's an alternative solution that implements tzr() in exactly one line of code,

``````#include <stdio.h>
#include <stdlib.h>

int tzr(int n) { /* --- every time n is even, add 1 and check n/2 --- */
return ( (n/2)*2 == n? 1+tzr(n/2) : 0 ); }

int main ( int argc, char *argv[] ) { /* --- test driver --- */
int n = (argc>1? atoi(argv) : 1000);
printf("tzr(%d) = %d\n", n,tzr(n)); }
``````

Is that any easier to understand?

(P.S. You could use bit masks and shifts instead of my divides and multiplies. That might be a little more efficient, but I thought my way might be a little more straightforward to read.)

User contributions licensed under CC BY-SA 3.0