用于计算32位整数中的设置位的方法的说明

时间:2013-04-12 08:50:11

标签: c++ c algorithm bit-manipulation

查看此link中计数设置位的方法,我找到了以下方法

作者说:

  

计算32位整数v中位的最佳方法是   以下内容:

v = v - ((v >> 1) & 0x55555555);                    // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);     // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
  

最佳位计数方法只需12次操作,即   与查找表方法相同,但避免了内存和潜力   缓存未命中的表。它是纯粹平行的混合体   上面的方法和使用乘法的早期方法(在本节中   在使用64位指令计数位时,虽然它不使用   64位指令。以字节为单位设置的位数完成   并行,并计算字节中设置的位的总和   乘以0x1010101并向右移24位。

任何解释这个方法如何计算设置位?

1 个答案:

答案 0 :(得分:4)

它的工作原理是因为您可以通过分成两半来计算设置位的总数,计算两半中的设置位数,然后将它们相加。也称为Divide and Conquer范例。让我们详细说明..

v = v - ((v >> 1) & 0x55555555); 

两位中的位数可以是0b000b010b10。让我们试着用2位来解决这个问题..

 ---------------------------------------------
 |   v    |   (v >> 1) & 0b1010   |   v - x   |
 ---------------------------------------------
   0b00           0b00               0b00   
   0b01           0b00               0b01     
   0b10           0b01               0b01
   0b11           0b01               0b10

这是所需要的,最后一列显示每两位对中的设置位数。如果两位数为>= 2 (0b10),则and生成0b01,否则生成0b00

v = (v & 0x33333333) + ((v >> 2) & 0x33333333); 

这个陈述应该很容易理解。在第一次操作之后,我们每两位有一个设置位的计数,现在我们总计每4位的计数。

v & 0b11001100         //masks out even two bits
(v >> 2) & 0b11001100  // masks out odd two bits

然后我们总结了上面的结果,给出了4位中设置位的总数。最后一个语句是最棘手的。

c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;

让我们进一步分解......

v + (v >> 4)

它类似于第二个语句,我们正在计算4个组中的设置位。我们知道,由于我们之前的操作,每个半字节都有其中的设置位数。让我们看一个例子,假设我们有字节0b01000010。这意味着第一个半字节设置为4比特,第二个设置为2比特。现在我们将这些小块一起添加。

0b01000010 + 0b01000000

它给出了第一个半字节0b01100010中字节中设置位的计数,因此我们屏蔽了数字中所有字节的最后四个字节(丢弃它们)。

0b01100010 & 0xF0 = 0b01100000

现在每个字节都有其中的设置位数。我们需要将它们加在一起。诀窍是将结果乘以0b10101010,它具有一个有趣的属性。如果我们的数字有四个字节A B C D,则会产生一个带有这些字节A+B+C+D B+C+D C+D D的新数字。一个4字节的数字最多可以设置32位,可以表示为0b00100000

我们现在需要的是第一个字节,其中包含所有字节中所有设置位的总和,我们通过>> 24得到它。此算法专为32 bit字设计,但可以轻松修改为64 bit字。