[英]Can someone explains why this works to count set bits in an unsigned integer?
I saw this code called "Counting bits set, Brian Kernighan's way" .我看到了这段代码,叫做“Counting bits set, Brian Kernighan's way” 。 I am puzzled as to how "bitwise and'ing" an integer with its decrement works to count set bits, can someone explain this?
我很困惑如何“按位和”一个带有递减量的整数来计算设置位,有人可以解释一下吗?
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
Each time though the loop one bit is counted, and one bit is cleared (set to zero).每次循环都会计数一位,并清除一位(设置为零)。
How this works is: when you subtract one from a number you change the least significant one bit to a zero, and the even less significant bits to one -- though that doesn't matter.它的工作原理是:当你从一个数中减去 1 时,你将最低有效位改为 0,将更不重要的位改为 1——尽管这无关紧要。 It doesn't matter because they are zero in the values you're decrementing, so they will be zero after the and-operation anyway.
没关系,因为它们在您递减的值中为零,因此无论如何在 and 操作之后它们都将为零。
XXX1 => XXX0
XX10 => XX01
X100 => X011
etc.
Let's walk through the loop with an example : let's set v = 42
which is 0010 1010
in binary.让我们通过一个例子来遍历循环:让我们设置
v = 42
,即二进制的0010 1010
。
First iteration : c=0, v=42 (0010 1010)
.第一次迭代:
c=0, v=42 (0010 1010)
。 Now v-1
is 41
which is 0010 1001
in binary.现在
v-1
是41
,也就是二进制的0010 1001
。 Let's compute v & v-1
:让我们计算
v & v-1
:
0010 1010 & 0010 1001 ......... 0010 1000
Now v&v-1
's value is 0010 1000
in binary or 40 in decimal.现在
v&v-1
的值为0010 1000
二进制或 40 十进制。 This value is stored into v
.该值存储在
v
。
Second iteration : c=1, v=40 (0010 1000)
.第二次迭代:
c=1, v=40 (0010 1000)
。 Now v-1
is 39
which is 0010 0111
in binary.现在
v-1
是39
,也就是二进制的0010 0111
。 Let's compute v & v-1
:让我们计算
v & v-1
:
0010 1000 & 0010 0111 ......... 0010 0000
Now v&v-1
's value is 0010 0000
which is 32
in decimal.现在
v&v-1
的值是0010 0000
,它是十进制的32
。 This value is stored into v
.该值存储在
v
。
Third iteration : c=2, v=32 (0010 0000)
.第三次迭代:
c=2, v=32 (0010 0000)
。 Now v-1
is 31
which is 0001 1111
in binary.现在
v-1
是31
,也就是二进制的0001 1111
。 Let's compute v & v-1
:让我们计算
v & v-1
:
0010 0000 & 0001 1111 ......... 0000 0000
Now v&v-1
's value is 0
.现在
v&v-1
的值为0
。
c=3, v=0
.c=3, v=0
。 The loop terminates .c
contains 3
which is the number of bits set in 42
. c
包含3
,这是在42
设置的位数。You can see that the binary representation of v-1
sets the least significant bit or LSB (ie the rightmost bit that is a 1) from 1 to 0 and all the bits right of the LSB from 0 to 1.您可以看到
v-1
的二进制表示将最低有效位或 LSB(即最右边的位为 1)从 1 设置为 0,并将 LSB 右边的所有位从 0 设置为 1。
When you do a bitwise AND between v
and v-1
, the bits left from the LSB are the same in v
and v-1
so the bitwise AND will leave them unchanged.当您在
v
和v-1
之间执行按位 AND 时,从 LSB 剩下的位在v
和v-1
中是相同的,因此按位 AND 将使它们保持不变。 All bits right of the LSB (including the LSB itself) are different and so the resulting bits will be 0. LSB 右侧的所有位(包括 LSB 本身)都不同,因此结果位将为 0。
In our original example of v=42 (0010 1010)
the LSB is the second bit from the right.在我们最初的
v=42 (0010 1010)
示例中,LSB 是右数第二位。 You can see that v-1
has the same bits as 42
except the last two : the 0 became a 1 and the 1 became a 0.您可以看到
v-1
与42
具有相同的位,除了最后两个:0 变为 1,1 变为 0。
Similarly for v=40 (0010 1000)
the LSB is the fourth bit from the right.类似地,对于
v=40 (0010 1000)
,LSB 是从右数第四位。 When computing v-1 (0010 0111)
you can see that the left four bits remain unchanged while the right four bits became inverted (zeroes became ones and ones became zeroes).在计算
v-1 (0010 0111)
您可以看到左边的四位保持不变,而右边的四位被反转(零变成一,一变成零)。
The effect of v = v & v-1
is therefore to set the least significant bit of v
to 0 and leave the rest unchanged.的效果
v = v & v-1
因此是到的至少显著位设为v
为0,剩下的不变。 When all bits have been cleared this way, v
is 0 and we have counted all bits.以这种方式清除所有位后,
v
为 0,我们已经计算了所有位。
Let A=a n-1 a n-2 ...a 1 a 0 be the number on which we want to count bits and k the index of the right most bit at one.设A=a n-1 a n-2 ...a 1 a 0是我们想要计数的位数, k是最右边位的索引为 1。
Hence A=a n-1 a n-2 ...a k+1 100...0=Ak+2 k where Ak=a n-1 a n-2 ...a k+1 000...0因此A=a n-1 a n-2 ...a k+1 100...0=Ak+2 k其中Ak=a n-1 a n-2 ...a k+1 000... 0
As 2 k −1=000..0111..11, we have A-1=Ak+2 k -1=a n-1 a n-2 ...a k+1 011...11由于 2 k -1=000..0111..11,我们有A-1=Ak+2 k -1=a n-1 a n-2 ...a k+1 011...11
Now perform the bitwise & of A and A-1现在执行A和A-1的按位 &
a n-1 a n-2 ...a k+1 100...0 A a n-1 a n-2 ...a k+1 100...0 A
a n-1 a n-2 ...a k+1 011...1 A-1 a n-1 a n-2 ...a k+1 011...1 A-1
a n-1 a n-2 ...a k+1 000...0 A&A-1=Ak a n-1 a n-2 ...a k+1 000...0 A&A-1=Ak
So A&A-1 is identical to A , except that its right most bit has been cleared, that proves the validity of the method.因此,A&A-1是相同的A,除了它的最右边的位已被清除,这证明了该方法的有效性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.