我不理解练习2-9,在k& r c编程语言中,第2章,2.10:
练习2-9。在两个的补充编号系统中,x& =(x-1)在x中删除了最右边的1位。解释为什么。使用此观察值编写更快的BitCount版本。
BitCount功能是:
/* bitcount: count 1 bits in x */
int bitcount(unsigned x)
{
int b;
for (b = 0; x != 0; x >>= 1)
if (x & 01)
b++;
return b;
}
该函数在检查是否是位1之后删除最右数,然后在最后一个位弹出。
我不明白为什么 x&(x-1)
删除正确的1位?例如,假设x是 1010
和x-1是二进制中的 1001
,而 x&(x-1)
将是 1011
,所以最右边的位会在那里,我会在其中,我错了吗?
另外,练习提到了两个人的补充,它与这个问题有关吗?
非常感谢!
首先,您需要相信k& r是正确的。其次,您可能会对这些单词有一些错误的理解。
让我再次为您澄清。最右1位并不意味着最大的位,而是最多的位,最多的位是二进制形式的1个。
让我们任意假设x是xxxxxxx1000(x可以是0或1)。然后从右到左,第四位是"最右边的1位"。根据这种理解,让我们继续解决问题。
为什么x& =(x-1)可以删除最右边的1位?
在两个的补体编号系统中,-1用所有1个位模式表示。
因此,X-1实际上是X (-1),即XXXXXX1000 1111111111。这是棘手的点。
在最大的1位1位之前,所有0变为1,最右的1位变为0,并且有一个携带1的左侧。而且,这1将继续延伸到左侧并引起溢出,同时,所有" x"位仍然是一个,因为'x' '1' '1'(随身携带)导致a'x'bit。
然后x&(X-1)将删除最右边的1位。
希望您现在可以理解。
谢谢。
这是解释它的简单方法。让我们任意假设y是xxxxxxx1000(x可以是0或1)。
xxxxxxx1000-1 = xxxxxxxx0111
xxxxxxxx1000&xxxxxxxx0111 = xxxxxxxx0000(请参阅"最右边的1"。)
因此,y& =(y-1)的重复数量在y变为0 之前将是y。
为什么 x & (x-1)
删除正确的订单位?只需尝试查看:
如果最高订单位为1,则X具有a...b1
的二进制表示,x-1
为a...b0
,因此位并给出a...b1
,因为and
和1 & 0
是0
其他X具有a...b10...0
的二进制表示;x-1
是a...b01...1
,出于与上述x & (x-1)
相同的原因,a...b00...0
将再次清除最右的订单位。
因此,您只需读取操作x = x & (x-1)
,直到x为0:步骤数将是1位的数量,而不是扫描所有位以找到哪个是0,哪个是1,而不是扫描。它比幼稚的实现更有效,因为从统计学上讲,您将使用一半的步骤。
代码的示例:
int bitcount(unsigned int x) {
int nb = 0;
while (x != 0) {
x &= x-1;
nb++
}
return nb;
}
ik我已经很晚了(≈3.5yr),但是您的示例有错误。
x = 1010 = 10
x -1 = 1001 = 9
1010&1001 = 1000
您可以看到,它在10中删除了最右边的位。
7 = 111
6 = 110
5 = 101
4 = 100
3 = 011
2 = 010
1 = 001
0 = 000
观察到最右1的位置在任何数字中,该数字的相同位置的位为0。因此,用X-1的x将重置(即设置为0)最右边的位。
7 & 6 = 111 & 110 = 110 = 6
6 & 5 = 110 & 101 = 100 = 4
5 & 4 = 101 & 100 = 100 = 4
4 & 3 = 010 & 011 = 010 = 2
3 & 2 = 011 & 010 = 010 = 2
2 & 1 = 010 & 001 = 000 = 0
1 & 0 = 001 & 000 = 000 = 0