【问题标题】:Number of bits set in a number数字中设置的位数
【发布时间】:2013-01-11 09:53:24
【问题描述】:

下面的神奇公式给出了一个数字中设置的位数(汉明权重)。

/*Code to Calculate count of set bits in a number*/
int c;
int v = 7;
v = v - ((v >> 1) & 0x55555555);                    // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);     // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
printf(" Number of Bits is %d",c);
/*-----------------------------------*/

来自: http://graphics.stanford.edu/~seander/bithacks.html

谁能解释一下这背后的原理?

【问题讨论】:

  • 天哪,除了炫耀外,没有理由记住这种奥秘(任何称职的人都应该知道来源)。
  • 当然,如果你在采访中给出这样的答案,那么下一个问题就是“解释”。所以没有必要记住,坦率地说,无论如何我都不希望在采访中看到这一点。
  • 向我们展示您是如何逐步完成示例的,一次一行,我们将帮助您找出错误(在问题的附录中请;不要在此发表评论)。
  • 有人觉得 64 位标签对这个问题有点讽刺吗?
  • 我建议您编写自己的 c 例程来查找设置的位数。它可以通过一些简单的转变和循环来完成。如果你能从头开始做到这一点,那比记住上面提到的东西要好得多,正如其他人所暗示的那样。

标签: c++ c bitmap bit-manipulation bit


【解决方案1】:

这是非常聪明的代码,显然比简单的幼稚循环更难理解。

对于第一行,我们只取一个四位的数量,并称之为abcd。代码基本上是这样做的:

abcd - ((abcd >> 1) & 0101) = abcd - (0abc & 0101) = abcd - 0a0c

因此,在每组两位中,它减去高位的值。这对我们有什么好处?

11 - 1 -> 10 (two bits set)
10 - 1 -> 01 (one bit set)
01 - 0 -> 01 (one bit set)
00 - 0 -> 00 (zero bits set)

因此,第一行将每个连续的两位组设置为原始值中包含的位数——它计算两位一组的位。调用得到的四位数量ABCD

下一行:

(ABCD & 0011) + ((ABCD>>2) & 0011) = 00CD + (AB & 0011) = 00CD + 00AB

因此,它需要两个位的组并将对相加。现在,每个四位组包含输入的相应四位中设置的位数。

在下一行中,v + (v >> 4) & 0xF0F0F0F(被解析为(v + (v >> 4)) & 0xf0f0f0f)做同样的事情,将四位组对添加在一起,以便每个八位组(字节)包含对应的输入字节。我们现在有一个类似0x0e0f0g0h 的号码。

请注意,将任何位置的字节乘以0x01010101 会将该字节复制到最高有效字节(以及在较低字节中保留一些副本)。例如,0x00000g00 * 0x01010101 = 0x0g0g0g00。所以,乘以0x0e0f0g0h,我们将把e+f+g+h留在最高字节;最后的 >>24 提取该字节并为您提供答案。

【讨论】:

  • 感谢您的解释!
  • 这是我在 SO 上找到的最有用的答案之一
【解决方案2】:

python 中的一个线性解决方案,用于计算给定二进制数中一个的个数

[i for i in str(bin(n)) if i=="1"].count("1")

【讨论】:

    猜你喜欢
    • 2013-10-07
    • 2022-07-21
    • 2015-06-11
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多