我不理解练习2-9,用K& R C编程语言, 第2章,2.10:
练习2-9。在二进制补码数系统中,x& =(x-1)删除x中最右边的1位。解释为什么。使用此观察值来编写更快的bitcount版本。
bitcount函数是:
String creator = user.getUserName();
该函数在检查它是否为bit-1后删除最右边的位,然后在最后一位弹出。
我无法理解为什么/* 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&(x-1)
且x-1为二进制1010
,而1001
为x&(x-1)
,因此最右边的位将为1,我哪里错了?
另外,这个练习提到了两个补充,是否与这个问题有关?
非常感谢!!!
答案 0 :(得分:2)
首先,您需要相信K&R是正确的。 第二,您可能对这些词有误解。
让我再次为您澄清一下。最右边的1位并不意味着最右边的位,而是最右边的二进制形式的1。
让我们任意假设x为xxxxxxx1000(x可以为0或1)。然后从右到左,第四位是“最右边的1位”。在这种理解的基础上,让我们继续解决这个问题。
为什么x&=(x-1)可以删除最右边的1位?
在二进制补码系统中,-1用全1位模式表示。
因此x-1实际上是x +(-1),即xxxxxxx1000 + 11111111111。棘手的地方到了。
在最严格的1位之前,所有0变为1,而最右边的1位变为0,并且左侧有一个进位1。并且此1将继续向最左边继续并引起溢出,同时,所有的“ x”位仍为a,因为“ x” +“ 1” +“ 1”(进位)引起了“ x”位。>
然后x&(x-1)将删除最右边的1位。
希望您现在能理解。
谢谢。
答案 1 :(得分:0)
为什么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
再次清除最右边的订单位。
因此,不是扫描所有位以找到哪一个是0而哪一个是1,而是只迭代操作x = x & (x-1)
直到x为0:步数将是1位的数量。它比天真的实现更有效,因为从统计上来说,你将使用一半的步骤。
代码示例:
int bitcount(unsigned int x) {
int nb = 0;
while (x != 0) {
x &= x-1;
nb++
}
return nb;
}
答案 2 :(得分:0)
这里是一种简单的解释方式。任意假设数字Y为xxxxxxx1000(x可以为0或1)。
xxxxxxx1000-1 = xxxxxxx0111
xxxxxxx1000和xxxxxxx0111 = xxxxxxx0000(请参见“最右边的1”消失了。)
因此,在Y变为0之前,Y&=(Y-1)的复制次数将是Y中1的总数。
答案 3 :(得分:0)
我已经很晚了(≈ 3.5yrs)但是你的例子有错误。
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 的位置,该数减 1 相同位置的位为 0。因此 x 与 x-1 的 AND 运算将重置(即设置为 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