演练
让我们用一个例子来遍历循环:让我们设置v = 42
它是0010 1010
二进制的。
第一次迭代:c=0, v=42 (0010 1010)
。现在v-1
是二进制的41
。0010 1001
让我们计算一下v & v-1
:
0010 1010
& 0010 1001
.........
0010 1000
Nowv&v-1
的值是0010 1000
二进制或十进制的 40。此值存储到v
.
第二次迭代:c=1, v=40 (0010 1000)
。现在v-1
是二进制的39
。0010 0111
让我们计算一下v & v-1
:
0010 1000
& 0010 0111
.........
0010 0000
Nowv&v-1
的值是0010 0000
十进制32
的。此值存储到v
.
第三次迭代:c=2, v=32 (0010 0000)
。现在v-1
是二进制的31
。0001 1111
让我们计算一下v & v-1
:
0010 0000
& 0001 1111
.........
0000 0000
现在v&v-1
的价值是0
。
- 第四次迭代:
c=3, v=0
。循环终止。c
包含3
其中设置的位数42
。
为什么有效
您可以看到二进制表示v-1
将最低有效位或 LSB(即最右边的位为 1)从 1 设置为 0,并将 LSB 右侧的所有位从 0 设置为 1。
当您在and之间进行按位与时,LSB 中留下的位是相同的,因此按位与将使它们保持不变。LSB 右边的所有位(包括 LSB 本身)都是不同的,因此结果位将为 0。v
v-1
v
v-1
在我们最初v=42 (0010 1010)
的 LSB 示例中,从右边数第二位。您可以看到除了最后两个之外,它v-1
具有相同的位42
:0 变为 1,1 变为 0。
同样,v=40 (0010 1000)
LSB 是从右数第四位。计算时v-1 (0010 0111)
,您可以看到左四位保持不变,而右四位变为反转(零变为一,一变为零)。
因此,的效果v = v & v-1
是将 的最低有效位设置v
为 0,其余保持不变。当所有位都以这种方式被清除时,v
为 0,我们已经计算了所有位。