K& R C编程语言练习2-9

时间:2017-12-02 09:22:04

标签: c

我不理解练习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,而1001x&(x-1),因此最右边的位将为1,我哪里错了?

另外,这个练习提到了两个补充,是否与这个问题有关?

非常感谢!!!

4 个答案:

答案 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-1a...b0,因此按位并将给出a...b1,因为公共位是左由and1 & 0保持不变0

其他x的二进制表示为a...b10...0; x-1a...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