如何检查8位无符号字符中的设置位数?

Fla*_*ius 1 c embedded bits

所以我必须在C中找到unsigned char变量的设置位(在1上)?

类似的问题是如何计算32位整数中的设置位数?但它使用的算法不易适应8位无符号字符(或不明显).

das*_*ght 6

对于 8 位变量,最快的方法是使用查找表。

构建一个包含 256 个值的数组,每个 8 位组合一个。每个值应包含其相应索引中的位数:

int bit_count[] = {
// 00 01 02 03 04 05 06 07 08 09 0a, ... FE FF
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., 7, 8
};
Run Code Online (Sandbox Code Playgroud)

获取组合的计数与从数组中查找值相同bit_count。这种方法的优点是速度非常快。

您可以使用一个简单的程序生成数组,该程序以缓慢的方式一位一位地计数:

for (int i = 0 ; i != 256 ; i++) {
    int count = 0;
    for (int p = 0 ; p != 8 ; p++) {
        if (i & (1 << p)) {
            count++;
        }
    }
    printf("%d, ", count);
}
Run Code Online (Sandbox Code Playgroud)

生成表格的演示)。

如果您想用一些 CPU 周期换取内存,可以使用 16 字节查找表进行两个 4 位查找:

static const char split_lookup[] = {
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};

int bit_count(unsigned char n) {
    return split_lookup[n&0xF] + split_lookup[n>>4];
}
Run Code Online (Sandbox Code Playgroud)

演示

  • @Olaf 256 字节(通过将计数打包到 4 位半字节中可以轻松缩小到 128 字节)很难被归类为“内存消耗”,除了在最小的嵌入式系统中(想到 PIC)。即使在很久以前的 8 位系统(具有 16..32K ROM 的 68HC11)上,256 字节也不算太多。就速度而言,这也很难被击败:在 HC11 上,这将需要两个四周期指令(“LDX”和“LDAA”,以“X”作为索引)。 (3认同)

Cli*_*ord 5

问题中建议的算法如何计算32位整数中的设置位数?很容易适应8位:

int NumberOfSetBits( uint8_t b )
{
     b = b - ((b >> 1) & 0x55);
     b = (b & 0x33) + ((b >> 2) & 0x33);
     return (((b + (b >> 4)) & 0x0F) * 0x01);
}
Run Code Online (Sandbox Code Playgroud)

它只是将常数缩短为最低有效8位,并删除最后24位右移的情况.同样,它可以使用8位移位适应16位.注意,在8位的情况下,32位算法的机械适应导致冗余* 0x01,这可以省略.