[英]Why does this function count the number of set bits in an integer
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? 我被要求告诉这个函数做了什么,我能够发现它计算unsigned int值中的设置位数,但我无法证明,也许有人可以?
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?
我能够发现它计算了unsigned int值中的设置位数,但是我无法证明这一点,也许有人可以?
Look at a single bit m
inside U
. 看一个单比特
m
内U
。 That bit contributes to the value of U
like: 这一点有助于
U
的价值:
U = ...... + U m 2^m + ..... (where the .... represents other bits). U = ...... + U m 2 ^ m + .....(其中......表示其他位)。
In each loop the bit is divived by 2 and then subtracted from U
. 在每个循环中,该位被除以2,然后从
U
减去。 When the loop is complete, this looks like the line below for bit m
: 当循环完成时,这看起来像位
m
下面一行:
U m 2^m - U m 2^(m-1) - U m 2^(m-2) - .... - U m 2^0 U m 2 ^ m - U m 2 ^(m-1) - U m 2 ^(m-2) - .... - U m 2 ^ 0
This can be rewritten like: 这可以改写如下:
U m (2^m - (2^(m-1) + 2^(m-2) + .... + 2^0)) U m (2 ^ m - (2 ^(m-1)+ 2 ^(m-2)+ .... + 2 ^ 0))
U m (2^m - (2^m -1)) U m (2 ^ m - (2 ^ m -1))
U m (2^m - 2^m + 1) U m (2 ^ m - 2 ^ m + 1)
U m U m的
So from this we can see, that bit m
contributes to the final result with its bit-value (ie 0 or 1). 因此我们可以看出,位
m
以其位值(即0或1)对最终结果做出贡献。 This, of cause, holds true for all bit in U
. 这个原因适用于
U
所有位。 Therefore: 因此:
foo
= U n-1 + U n-2 + ... + U m + ... + U 1 + U 0 foo
= U n-1 + U n-2 + ... + U m + ... + U 1 + U 0
Consequently, the result will be equal to the number of bits set in U
. 因此,结果将等于
U
设置的位数。
ps I tried to use superscript to make the formulas look better. ps我尝试使用上标使公式看起来更好。 But I couldn't make
<sup>
work. 但我不能让
<sup>
工作。 Feel free to edit the formulas if you know how. 如果您知道如何,请随意编辑公式。
It is known that an unsigned integer u
can be represented as a sum of powers of two: 众所周知 ,无符号整数
u
可以表示为2的幂之和:
u = A * 2ª + ... + N * 2ⁿ,
where 0 <= a < ... < n
are integers, and A, ..., N
are either zeroes, or ones. 其中
0 <= a < ... < n
是整数, A, ..., N
是零或1。 If we remove the zero-product terms, the number of terms will be equal to the number of set bits (ones). 如果我们删除零积项,则项的数量将等于设置位数(1)。 For example,
1101
b = 2⁰ + 2² + 2³ consists of three terms (powers of two), and the number of set bits is also equal to three. 例如,
1101
b =2⁰+2²+2³由三个项(2的幂)组成,并且设置位的数量也等于3。
The idea is to find the number of non-zero terms in this representation. 这个想法是在这个表示中找到非零项的数量 。
If we express u
as a sum of powers of two: 如果我们表达
u
作为两个大国的总和:
u = 2ª + ... + 2ⁿ
where 0 <= a < ... < n
, then the integer division u = u / 2
can be expressed as: 其中
0 <= a < ... < n
,则整数除法u = u / 2
可表示为:
u = ( 2ª + ... + 2ⁿ ) / 2
or, equivalently: 或者,等效地:
u = ( 2ª / 2 ) + ... + ( 2ⁿ / 2 )
(Since, generally, (x + y) / 2 = (x / 2) + (y / 2)
.) (因为,通常,
(x + y) / 2 = (x / 2) + (y / 2)
。)
The process is repeated while u
is positive. 当
u
是积极的时候,重复这个过程。 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
. 在下一次迭代中, 由于整数除法的规则,它变为等于零 :
1 / 2 = 0
。
The resulting value ( u
) is subtracted from the original value stored in foo
: foo -= u
. 从存储在
foo
: foo -= u
的原始值中减去结果值( u
)。
Thus, we eventually subtract everything from the original value foo
, except the "ones divided by two" ( 1 / 2
) . 因此,我们最终从原始值
foo
减去所有内容,除了“除以2”( 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). 显然,出现的次数
1 / 2
等于u
的原始表达式中的非零项的数量,其等于设置位的数量(如上所述)。 Hence, the value remaining ìn foo
is a sum of " 1 / 2
" leftovers, ie the number of terms which is also the number of set bits. 因此,剩余的值'n
foo
是“ 1 / 2
”剩余的总和,即也是设置位数的项数。
Let's visualize the process on example of u = 13
. 让我们在
u = 13
例子中可视化过程。
Binary representation of the decimal number 13
is 1101
. 十进制数
13
二进制表示是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
. 到目前为止我们有一个零:
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
. 在这次迭代中我们得到了第二个零:
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, ie 3
. 零的数量等于设置的比特数,即
3
。
Suppose when the input is N
, the output is M
. 假设当输入为
N
,输出为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
). 然后当输入为
2*N
,输出仍为M
,当输入为2*N+1
,输出必须为M+1
(两个语句都来自循环的第一次迭代的分析,这减少了输入到N
)。
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): 作为一个例子,让我们看看
U=10110
会发生什么(1s在向右移动时在对角线上传播):
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
. 正如您所看到的,对于位置N上的每个位1,表示数字
2^N
(因此用2 ^ N充电u),U0将被充电2^0+2^1+ ... + 2^(N-1)
等于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. 因此,对于设置为1的每个位,
U0
将松散1.将U写为二进制和,对于设置为1的每个位,我们松开1。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.