给定unsigned int,我必须执行以下操作:
(操作不应该是架构依赖)。
我使用按位移位完成了这项工作,但我必须迭代几乎所有的位(es.32)。 例如,计算1:
unsigned int number= ...;
while(number != 0){
if ((number & 0x01) != 0)
++count;
number >>=1;
}
其他操作类似。
所以我的问题是:有没有更快的方法呢?
答案 0 :(得分:9)
如果您想要最快方式,则需要使用非便携式方法。
<强>窗/ MSVC:强>
<强> GCC 强>
这些通常直接映射到本机硬件指令。所以它没有比这些快得多。
但由于它们没有C / C ++功能,因此只能通过编译器内在函数访问它们。
答案 1 :(得分:8)
看看ffs(3),ffsl(3),fls(3),flsl(3)。
ffs()和ffsl()函数在i中找到第一个位集(从最低有效位开始)并返回该位的索引。
fls()和flsl()函数找到i中设置的最后一位并返回该位的索引。
您可能也对bitstring(3)感兴趣。
答案 2 :(得分:4)
引自http://graphics.stanford.edu/~seander/bithacks.html
计算32位整数v中位的最佳方法如下:
unsigned int v; // count bits set in this (32-bit value) unsigned int c; // store the total here v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
最佳位计数方法仅执行12次操作,这与查找表方法相同,但避免了表的内存和潜在的高速缓存未命中。它是上面的纯粹并行方法和使用乘法的早期方法之间的混合(在使用64位指令计数位的部分中),尽管它不使用64位指令。字节中设置的位数是并行完成的,字节中设置的位总和是通过乘以0x1010101和右移24位来计算的。
答案 3 :(得分:2)
一种方法是使用查找表。
uint8_t popcount_table[256] = { ... };
uint8_t popcount (uint32_t x)
{
uint8_t *p = (uint8_t*)&x;
return popcount_table[p[0]] +
popcount_table[p[1]] +
popcount_table[p[2]] +
popcount_table[p[3]];
}
答案 4 :(得分:2)
数字x的“最严格的1位”由
给出pos(1st '1') = log_2(x XOR (x-1) + 1) - 1
例如:
x = 1100101000;
x-1 = 1100100111;
x XOR (x-1) = 0000001111;
x XOR (x-1) + 1 = 0000010000;
然后,最后一行的base2-log给您正确的位置+1。因此,从对数结果中减去1,您将获得最右边的“ 1”位。
对于最右边的“ 0”位,您可以使用
pos(1st '0') = log_2(x XOR (x+1) + 1) - 1
答案 5 :(得分:0)
最右边的简单答案
第一种方法
unsigned int getFirstSetBit(int n){
return log2(n & -n) + 1;
}
第二种方法
unsigned int getFirstSetBit(int n){
return ffs(n);
}