计算位数:这条线是如何工作的? n=n&(n-1); [复制]

Posted

技术标签:

【中文标题】计算位数:这条线是如何工作的? n=n&(n-1); [复制]【英文标题】:Counting number of bits: How does this line work ? n=n&(n-1); [duplicate] 【发布时间】:2013-03-12 19:21:54 【问题描述】:

我需要解释一下这条特定线路的工作原理。 我知道这个函数计算 1 的位数,但是这条线究竟是如何清除最右边的 1 位的呢?

int f(int n) 
    int c;
    for (c = 0; n != 0; ++c) 
        n = n & (n - 1);
    return c;

有人可以简单地向我解释一下或给出一些“证据”吗?

【问题讨论】:

想想长减法和“借用”。 它会清除最右边的位,因为n - 1 的最右边位永远不会与n 相同。 Kernighan's bit-count trick! 位旋转技巧通常应该使用无符号类型来完成,以防您的机器不使用二进制补码作为有符号类型(或者如果编译器尝试根据标准的知识进行一些巧妙的优化)符号类型不需要二进制补码)。 这个问题询问n = n & (n - 1),换句话说n &= (n-1)。建议的“已回答”问题要求其他内容,如其标题中所述:n & (n-1) 做了什么。前者的目的是去除最右边的 value-1 位,而后者是检查 n 是否是 2 的幂。我可以看到这两个表达式看起来相似并且它们的真值表相同,但是这两个问题,因此答案,无疑是不同的 【参考方案1】:

任何无符号整数“n”都将具有以下最后 k 位数字:1 后跟 (k-1) 个零:100...0 请注意,k 可以为 1,在这种情况下没有零。

(n - 1) 将以这种格式结束:0 后跟 (k-1) 1's: 011...1

n & (n-1) 因此将以“k”个零结尾:100...0 & 011...1 = 000...0

因此 n & (n - 1) 将消除最右边的“1”。每次迭代基本上都会删除最右边的“1”数字,因此您可以计算 1 的数量。

【讨论】:

如果平台使用有符号幅度表示而不是二进制补码,这是否适用于负值?【参考方案2】:

我一直在复习位操作并遇到了这个问题。现在(3年后)可能对原始海报没有用,但无论如何我都会回答以提高其他观众的质量。

n & (n-1) 等于 0 是什么意思?

我们应该确保我们知道这一点,因为这是打破循环的唯一方法 (n != 0)。 假设n=8。其位表示为00001000n-1(或 7)的位表示为 00000111& 运算符返回两个参数中设置的位。由于0000100000000111 没有设置任何类似的位,因此结果将是00000000(或零)。 您可能已经注意到数字 8 不是随机选择的。这是一个示例,其中n 是 2 的幂。所有 2 的幂(2、4、8、16 等)都会产生相同的结果。

当你传递的不是 2 的指数时会发生什么?例如,当n=6 时,位表示为00000110n-1=500000101& 应用于这两个参数,它们只有一个共同的位,即 4。现在,@ 987654337@ 不为零,因此我们递增c 并尝试使用n=4 执行相同的过程。正如我们在上面看到的,4 是 2 的指数,因此它将在下一次比较中打破循环。 直到n等于2的幂。

什么是c

每循环只加一,从 0 开始。c 是在数字等于 2 的幂之前被切断的位数。

【讨论】:

以上是关于计算位数:这条线是如何工作的? n=n&(n-1); [复制]的主要内容,如果未能解决你的问题,请参考以下文章

这段代码是如何工作的?

计算11的1位数到N的幂

UVa 10213 How Many Pieces of Land ? (计算几何+大数)

c语言 一个整数的前n位数之和sum

n&(n-1)

1120 机器人走方格 V3