【问题标题】:How does this method count the number of 1s in binary representation? [duplicate]此方法如何计算二进制表示中 1 的数量? [复制]
【发布时间】:2012-08-04 17:18:03
【问题描述】:

可能重复:
n & (n-1) what does this expression do?

考虑以下算法:

int count(int num)
{
  int ones = 0;
  while(num)
  {
    ++ones; 
    num &= num - 1;
  }

  return ones;
}

num & (num-1)的意义是什么?它是如何工作的?

【问题讨论】:

  • 请注意,这也称为人口计数或汉明权重。
  • btw,if 子句要修改为 while(num > 0)
  • @Pompair:while(num)while(num != 0)一样,所以是正确的。

标签: c algorithm bit-manipulation


【解决方案1】:
num &= num - 1;

清除 num 中设置的最低有效位。

该算法通过清除设置的位并递增计数器直到它们全部消失来计算设置的位。

要了解它为何清除最低有效位,您需要考虑递减对位的作用,当然还要了解& 操作的作用。

二进制中的减法就像我们小时候都用十进制教过的过程一样。 您从右(最不重要)到左工作,尽可能简单地减去单个数字,并在必要时从下一个数字“借用”。

当从以一组零结尾的二进制数中减去 1 时,这种“借用”和减法会将比最右边的 1 低位置的所有零变为 1,并将最右边的 1 变为零(因为它是借用的) .

然后应用& 运算符将所有较小的数字保留为零,因为它们在num 中为零,并将num 的最低有效位设置为零,因为它在num-1 中为零。

这两个操作都保持较高的有效数字不变。

这是一个很好的bit twiddling hacks 列表,包括这个,这是由于Brian Kernighan

【讨论】:

    【解决方案2】:

    这里有一个更详细(但写得不是很好!)的答案。

    有两种情况:要么设置最低有效位,然后“num-1”取消设置它。或者未设置,则num-1将所有尾随零变为1,并将最低有效1变为0,其余位不变。当您“与”时,所有未更改的位都是相同的,与 0 相加的最低有效 1 变为 0,其他剩余位为零。这在此处进行了说明:

    num             =      1000110111[1]0000
    num - 1         =      1000110111[0]1111
    num & (num - 1) =      1000110111[0]0000
    

    我要指出,通常有一个组装操作来计算单个循环中的数量。该操作称为“popcount”,例如在 GCC 中,可以使用“__builtin_popcount”访问它,详情请参阅this link

    【讨论】:

    • 我编辑了添加链接的默认描述。希望没问题! +1 获取有关 gcc 的信息
    • 是的,谢谢 :) 顺便说一句,当我说“这里有一个更详细的答案”时,唐·罗比的答案只有三行。从那以后,他(非常好)扩展了他原来的答案。
    • Visual Studio 用户还可以通过 __popcnt compiler intrinsics 使用 POPCNT 指令。
    • @Blastfurnace:谢谢!我只是想知道 VS 上的等价物是什么!
    【解决方案3】:

    该算法像泵一样运行,有效地将“num”变量中的位移动到右侧。线

    num &= num - 1;
    

    是工作完成的地方,同时进行赋值和布尔AND运算。都是关于位算术的。

    波姆

    【讨论】:

    • 它根本没有移动位。它正在清除它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 2013-05-23
    • 2012-02-10
    • 1970-01-01
    • 2023-03-14
    • 2015-07-09
    • 1970-01-01
    相关资源
    最近更新 更多