考虑以下算法:
int count(int num)
{
int ones = 0;
while(num)
{
++ones;
num &= num - 1;
}
return ones;
}
num & (num-1)
有什么意义?它是如何工作的?
答案 0 :(得分:7)
num &= num - 1;
清除num。
中设置的最低有效位此算法通过清除它们并递增计数器来计算设置的位数,直到它们全部消失为止。
要理解清除最低有效位的原因,你需要考虑递减对比特的作用,当然要理解&
操作的作用。
在二进制中减去工作就像我们在十进制中作为孩子一样教导的过程。 你从正确(最不重要)到左边工作,只要在可能的情况下减去个别数字,并在必要时从下一个数字“借用”。
当从以一组零结尾的二进制数中减去1时,这种“借用”和减法将所有的零点置于比最右边的1到1更低的位置,并将最右边的1变为零(因为它是借用的)
然后应用&
运算符会将所有较小的数字保留为零,因为它们在num
中为零,并将num
的最低有效位设置为零,因为它在{{0}中为零1}}。
这两项操作都会使更高位数保持不变。
以下是包含此bit twiddling hacks的Brian 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操作。这都是关于位算术的。
聚甲醛