代表数字7的8位像这样:

00000111

设置了三个比特。

确定32位整数中设置位数的算法是什么?


当前回答

从Python 3.10开始,你将能够使用int.bit_count()函数,但目前,你可以自己定义这个函数。

def bit_count(integer):
    return bin(integer).count("1")

其他回答

如果你使用c++,另一个选择是使用模板元编程:

// recursive template to sum bits in an int
template <int BITS>
int countBits(int val) {
        // return the least significant bit plus the result of calling ourselves with
        // .. the shifted value
        return (val & 0x1) + countBits<BITS-1>(val >> 1);
}

// template specialisation to terminate the recursion when there's only one bit left
template<>
int countBits<1>(int val) {
        return val & 0x1;
}

用法如下:

// to count bits in a byte/char (this returns 8)
countBits<8>( 255 )

// another byte (this returns 7)
countBits<8>( 254 )

// counting bits in a word/short (this returns 1)
countBits<16>( 256 )

当然,你可以进一步扩展这个模板来使用不同的类型(甚至是自动检测位大小),但为了清晰起见,我让它保持简单。

edit:忘了说这很好,因为它应该在任何c++编译器中工作,它基本上只是为你展开循环,如果一个常量值用于比特计数(换句话说,我很确定这是你能找到的最快的通用方法)

我使用下面的函数。我还没有检查基准测试,但它是有效的。

int msb(int num)
{
    int m = 0;
    for (int i = 16; i > 0; i = i>>1)
    {
        // debug(i, num, m);
        if(num>>i)
        {
            m += i;
            num>>=i;
        }
    }
    return m;
}

如果您恰好使用Java,则内置方法Integer。bitCount会这样做。

unsigned int count_bit(unsigned int x)
{
  x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
  x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
  x = (x & 0x0000FFFF) + ((x >> 16)& 0x0000FFFF);
  return x;
}

我来解释一下这个算法。

该算法基于分治算法。假设有一个8位整数213(二进制的11010101),算法是这样工作的(每次合并两个邻居块):

+-------------------------------+
| 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |  <- x
|  1 0  |  0 1  |  0 1  |  0 1  |  <- first time merge
|    0 0 1 1    |    0 0 1 0    |  <- second time merge
|        0 0 0 0 0 1 0 1        |  <- third time ( answer = 00000101 = 5)
+-------------------------------+

32位还是32位?我只是在阅读了“破解编码面试”第4版练习5.5(第5章:位操作)后,在Java中使用了这种方法。如果最小有效位是1个增量计数,则右移该整数。

public static int bitCount( int n){
    int count = 0;
    for (int i=n; i!=0; i = i >> 1){
        count += i & 1;
    }
    return count;
}

我认为这个比常数0x33333333的解更直观,不管它们有多快。这取决于你对“最佳算法”的定义。