使用 C 计算 8 位二进制数中的设置位

问题描述 投票:0回答:7

我有一个长度为8的二进制数,例如

00110101
有8位设置。

我需要快速位计数来确定设置位的数量,即 popcount 又名人口计数。 像这样运行算法

x=x&(x-1)
会将其限制为数字包含的设置位数,但我不太确定如何使用它。

计算 32 位整数中设置位的数量不同,我只有 8 位整数,因此 O(log width) bithack 方法仍然有几个步骤,可能不会比 O(set_bits) 或CPU 上的 4 位或 8 位查找表没有硬件 popcount,或者以无法接受假设支持的方式进行编译。

c bit hammingweight bitcount
7个回答
4
投票

x=x&(x-1)
从二进制字符串中删除最低设置位。如果计算在数字变为 0 之前删除最低位的次数,您将得到已设置的位数。

char numBits(char x){
    char i = 0;
    if(x == 0)
        return 0;
    for(i = 1; x &= x-1; i++);
    return i;
}

3
投票

执行

x = x & (x-1)
将删除最低位集。因此,在您的情况下,迭代将执行为,

loop #1: 00110101(53) & 00110100(52) = 00110100(52) :: num bits = 1

loop #2: 00110100(52) & 00110011(51) = 00110000(48) :: num bits = 2

loop #3: 00110000(48) & 00101111(47) = 00100000(32) :: num bits = 3

loop #3: 00100000(32) & 00011111(31) = 00000000( 0) :: num bits = 4

允许的迭代次数将是给定数字中的总位数。


1
投票

美国专利 6,516,330 – 计算数据字中的设置位

(我只是发明了它——不要让我解释。)


1
投票

问题中描述的方法(通常归因于 K&R )的复杂度为 n,其中 n 是数字中设置的位数。

通过使用额外的内存,我们可以将其降低到 O(1):

用位数(编译时操作)初始化一个查找表,然后引用它; 您可以在这里找到方法:计算查找表设置的位数

您可以在 Henry S. Warren, Jr.(2007) “The Quest for an Accelerated Population Count”, Beautiful Code pp.147-158 O'Reilly

中找到不同方法的详细讨论

1
投票

我的代码片段仅适用于无符号整数: 希望这有帮助。

uint G = 8501; //10 0001 0011 0101
uint g = 0;

for (int i = 0; i < 32; i++)
{
  g += (G << (31 - (i % 32))) >> 31;
}

Console.WriteLine(g); //6

0
投票

取决于您如何计算设置位 - 在我们的例子中,实际设置位的数量为 4;位宽(我在此将其定义为最高位组的数字加 1)为 6(因为您需要 6 位来表示您的数字)。后一个可以通过

确定
char highestbit (uint32_t num)
{
    char i;
    for (i = 0; i < sizeof(num)*8; i++) {
        if ((1L << i) > num) {
            return i;
        }
    }
    return sizeof(num)*8;
}

(未经测试)


0
投票
x := (x and $55555555) + ((x shr 1) and $55555555); 
x := (x and $33333333) + ((x shr 2) and $33333333); 
x := (x and $0F0F0F0F) + ((x shr 4) and $0F0F0F0F); 
x := (x and $00FF00FF) + ((x shr 8) and $00FF00FF); 
x := (x and $0000FFFF) + ((x shr 16) and $0000FFFF);

摘自matrix67的博客,是中文的。

© www.soinside.com 2019 - 2024. All rights reserved.