简体   繁体   English

有人可以解释为什么这可以计算无符号整数中的设置位吗?

[英]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.

Walkthrough演练

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-141 ,也就是二进制的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-139 ,也就是二进制的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-131 ,也就是二进制的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

  • Fourth iteration : 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设置的位数。

Why it works为什么有效

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.当您在vv-1之间执行按位 AND 时,从 LSB 剩下的位在vv-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-142具有相同的位,除了最后两个: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现在执行AA-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM