在某个位置或更低位置计算设置位的有效方法是什么?

时间:2015-12-22 02:09:47

标签: c++ algorithm performance bit-manipulation

给定std::bitset<64> bits设置任意位数且位位置X(0-63)

在X位置或更低位置计数位的最有效方法是什么?如果未设置X位,则返回0

注意:如果设置该位,则返回始终至少为1

蛮力方式很慢:

int countupto(std::bitset<64> bits, int X)
{
  if (!bits[X]) return 0;
  int total=1;
  for (int i=0; i < X; ++i)
  {
    total+=bits[i];
  }
  return total;
}

count()的{​​{1}}方法将为您提供所有位的bitset,但popcount不支持范围

注意:这不是How to count the number of set bits in a 32-bit integer?的重复,因为它询问所有位而不是范围0到X

4 个答案:

答案 0 :(得分:10)

我的立即反应是测试指定的位,并立即返回0清除。

如果超过该值,则使用该位(以及不太重要的位)设置位掩码,并使用原始输入创建and位掩码。然后使用count()成员函数来获取结果中设置的位数。

至于创建蒙版:你可以向左移动1个位置,然后减去1。

答案 1 :(得分:5)

假设unsigned longunsigned long long足够容纳64位,您可以调用bits.to_unlong()(或bits.to_ullong())来获取整数位掩码数据,掩码关闭X((1 << X) - 1)以上的位,然后计算您链接到的问题的答案中给出的那些位。

答案 2 :(得分:5)

在它下面的位上转换位和掩码很容易,所以这样的东西应该有效:

int popcnt(bitset<64> bs, int x) {
    // Early out when bit not set
    if (!bs[x]) return 0;
    // Otherwise, make mask from `x`, mask and count bits
    return (bs & bitset<64>((1UL << x) - 1)).count() + 1;
}

这里的假设是bitset::count有效实施(使用popcnt内在函数或有效回退);这不能保证,但STL人员倾向于优化这类事情。

答案 3 :(得分:1)

我编辑过一个我之前看过的问题,检查一个数字中是否设置了奇数或偶数位。它适用于C,但要将它按到C ++中并不是很难。解决方案的关键在于while循环中的内容。在纸上试一试,了解它如何挑出LSB,然后将其从x中删除。其余的代码是直截了当的。代码在O(n)中运行,其中n是x中的设置位数。这比线性时间好得多,我以为只有在第一次看到这个问题时才有可能。

#include <stdio.h>

int
count(long x, int pos)
{
    /* if bit at location pos is not set, return 0 */
    if (!((x >> pos) & 1))
    {
        return 0;
    }

    /* prepare x by removing set bits after position pos */
    long tmp = x;
    tmp = tmp >> (pos + 1);
    tmp = tmp << (pos + 1);
    x ^= tmp;

    /* increment count every time the first set bit of x is removed (from the right) */
    int y;
    int count = 0;
    while (x != 0)
    {
        y = x & ~(x - 1);
        x ^= y;
        count++;
    }
    return count;
}

int
main(void)
{
    /* run tests */
    long num = 0b1010111;
    printf("%d\n", count(num, 0)); /* prints: 1 */
    printf("%d\n", count(num, 1)); /* prints: 2 */
    printf("%d\n", count(num, 2)); /* prints: 3 */
    printf("%d\n", count(num, 3)); /* prints: 0 */
    printf("%d\n", count(num, 4)); /* prints: 4 */
    printf("%d\n", count(num, 5)); /* prints: 0 */
    printf("%d\n", count(num, 6)); /* prints: 5 */
}