Why does this function count the number of set bits in an integer

僤鯓⒐⒋嵵緔 提交于 2019-12-21 20:18:48

问题


I was asked the following question in an interview:

int foofoo(unsigned int u) {
    unsigned int foo = u;
    do{
        u = u/2;
        foo -= u;
    }while(u > 0);
    return foo;
}

I was asked to tell what does this function do and I was able to find that it counts the number of set bits in an unsigned int value, but I was not able to prove that, maybe someone can?


回答1:


I was able to find that it counts the number of set bits in an unsigned int value, but I was not able to prove that, maybe someone can?

Look at a single bit minside U. That bit contributes to the value of U like:

U = ...... + Um 2^m + ..... (where the .... represents other bits).

In each loop the bit is divived by 2 and then subtracted from U. When the loop is complete, this looks like the line below for bit m:

Um 2^m - Um 2^(m-1) - Um 2^(m-2) - .... - Um 2^0

This can be rewritten like:

Um (2^m - (2^(m-1) + 2^(m-2) + .... + 2^0))

Um (2^m - (2^m -1))

Um (2^m - 2^m + 1)

Um

So from this we can see, that bit m contributes to the final result with its bit-value (i.e. 0 or 1). This, of cause, holds true for all bit in U. Therefore:

foo = Un-1 + Un-2 + ... + Um + ... + U1 + U0

Consequently, the result will be equal to the number of bits set in U.

p.s. I tried to use superscript to make the formulas look better. But I couldn't make <sup> work. Feel free to edit the formulas if you know how.




回答2:


The Idea

It is known that an unsigned integer u can be represented as a sum of powers of two:

u = A * 2ª + ... + N * 2ⁿ,

where 0 <= a < ... < n are integers, and A, ..., N are either zeroes, or ones. If we remove the zero-product terms, the number of terms will be equal to the number of set bits (ones). For example, 1101b = 2⁰ + 2² + 2³ consists of three terms (powers of two), and the number of set bits is also equal to three.

The idea is to find the number of non-zero terms in this representation.

Algorithm

If we express u as a sum of powers of two:

u = 2ª + ... + 2ⁿ

where 0 <= a < ... < n, then the integer division u = u / 2 can be expressed as:

u = ( 2ª + ... + 2ⁿ ) / 2

or, equivalently:

u = ( 2ª / 2 ) + ... + ( 2ⁿ / 2 )

(Since, generally, (x + y) / 2 = (x / 2) + (y / 2).)

The process is repeated while u is positive. So each term eventually becomes equal to one. In the next iteration it becomes equal to zero due to the rules of integer division: 1 / 2 = 0.

The resulting value (u) is subtracted from the original value stored in foo: foo -= u.

Thus, we eventually subtract everything from the original value foo, except the "ones divided by two" (1 / 2).

Obviously, the number of occurrences of 1 / 2 is equal to the number of non-zero terms in the original expression of u which is equal to the number of set bits (as we found out above). Hence, the value remaining ìn foo is a sum of "1 / 2" leftovers, i.e. the number of terms which is also the number of set bits.

Example

Let's visualize the process on example of u = 13.

Binary representation of the decimal number 13 is 1101. So the sum of powers of two in decimal notation is:

u = 2⁰ + 2² + 2³

First iteration:

u = u / 2
  = (2⁰ + 2² + 2³) / 2
  = (2⁰ / 2) + (2² / 2) + (2³ / 2)
  = 0        + 2        + 2²

We have one zero so far: 2⁰ / 2 = 1 / 2 = 0.

Second iteration:

u = u / 2
  = (2      + 2²) / 2
  = (2 / 2) + (2² / 2)
  = 1       + 2

No more zeroes in this iteration. Third iteration:

u = u / 2
  = (1      + 2) / 2
  = (1 / 2) + (2 / 2)
  = 0       + 1

We have got the second zero in this iteration: 1 / 2 = 0.

Fourth iteration gives the third zero:

u = u / 2
  = 1 / 2 = 0.

The number of zeroes is equal to the number of set bits, i.e. 3.




回答3:


Suppose when the input is N, the output is M. Then when the input is 2*N the output is still M, and when the input is 2*N+1 the output must be M+1 (both statements follow from the analysis of the first iteration of the loop which reduces the input to N).




回答4:


I am a bit late answering.

I would answer by rewriting the program in an equivalent form...

#include <stdio.h>

unsigned
count(unsigned u) {
  unsigned foo=u, u0=0;
  do
    u0+=u>>=1;
  while(u);
  return foo-u0;
}

void
main()
{
  printf("%u\n", count(7));
}

As an example, let us see what happens for U=10110 (the 1s propagate on diagonal while shifting right):

10110
 1011
  101
   10
    1

As you can see, for each bit 1 on position N, representing the number 2^N (so charging u with 2^N), U0 will be charged with 2^0+2^1+ ... + 2^(N-1) which equals 2^N-1.

So, for each bit set to 1, U0 will loose 1. Writing U as a binary sum, we loose 1 for each bit set to 1.



来源:https://stackoverflow.com/questions/44039795/why-does-this-function-count-the-number-of-set-bits-in-an-integer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!