一般比特计数

时间:2017-07-24 05:22:07

标签: algorithm bit-manipulation

我知道这是计算整数中数字设置位的相当不错的解决方案:

CountBits(n)    
    count = 0
    while n > 0
        n ← n & (n - 1)
        count ← count + 1

是否存在计算有多少非重叠k位组非零的类似优雅解决方案。我目前有:

CountGroups(n, k)
    count = 0
    mask = (2 << k) - 1
    while n > 0
        if n & mask ≠ 0
            count ← count + 1
        n >> k

在最左边的组的位置是线性的。在后一种算法中,如果只设置了第一组和最后一组,我必须访问并检查其间的所有组,而前者只执行两次操作。它不是瓶颈或任何东西,只是好奇是否有更好的方法。

1 个答案:

答案 0 :(得分:1)

通过将字分割为奇数和偶数序列,可以并行计算k个设置位组。当且仅当组中的所有位都已设置时,携带到下一个空位置(标有...)。

最初的问题是关于在一个组中设置的任何位,但这可以通过补充 n ,添加一个并补充结果来进行转换。 (现在结果== 1当且仅当原始组全部为零时。)

 // ...xxx...xxx...xxx   even sequence
 // yyy...yyy...yyy...   odd sequence

 uint64_t a = ~n & even_mask;         // inverse of n
 uint64_t b = (~n >> k) & even_mask;  // inverse of n
 a += 0010101;  // this is octal, where a "one" is added to each group
 b += 0010101;  // same for odd sequence

 //  a = 001xxx000yyy001xxx  -- e.g. first and last group were all ones
 //  b = 000yyy000yyy001yyy  -- e.g. last group of 'y' was all one

 a &= ~even_mask;   // remove the xxx yyy parts, leaving only carry
 b &= ~even_mask;
 a |= (b << 1);
 return bitcount(a ^ 03030303);   // return total number of carry bits

Bitcount可以并行完成,如果有的话可以使用特殊指令(__popcount)或者使用Kerningham Richie -method(n&amp;(n-1))。

这只说明了k == 3,但可以扩展到任意k,即使当k变大时兴趣的回报会减少。

根据 k ,可能有更好的算法来为条件派生布尔表达式。

在这种情况下,对于每个组,条件是n(i)| n(i + 1)| ... n(i + k-1),可以并行和/或使用折叠技术进行评估,当k是2的幂时,这种技术特别有用。

//  n = aabb ccdd eeff gghh iijj   -- original sequence, k = 4
//      0011 0011 0011 0011 0011   -- mask
n = (n | (n >> 2)) & 0x33333333;   // fold to aa|bb, cc|dd, etc.
n = (n | (n >> 1)) & 0x11111111;   // fold boolean expression as 0th bit position in each group

return bitcount(n);