该方法如何计算二进制表示中的1的数量?

时间:2012-08-04 17:18:04

标签: c algorithm bit-manipulation

  

可能重复:
  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)有什么意义?它是如何工作的?

3 个答案:

答案 0 :(得分:7)

num &= num - 1;

清除num。

中设置的最低有效位

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

要理解清除最低有效位的原因,你需要考虑递减对比特的作用,当然要理解&操作的作用。

在二进制中减去工作就像我们在十进制中作为孩子一样教导的过程。 你从正确(最不重要)到左边工作,只要在可能的情况下减去个别数字,并在必要时从下一个数字“借用”。

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

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

这两项操作都会使更高位数保持不变。

以下是包含此bit twiddling hacksBrian Kernighan的完整列表,该列表归{{3}}所示。

答案 1 :(得分:7)

这是一个更详细(但写得不太好)的答案。

有两种情况:设置最低有效位,然后“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

答案 2 :(得分:-1)

该算法像泵一样运行,在“num”变量中有效地向右移动位。这条线

num &= num - 1;

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

聚甲醛