简体   繁体   English

用于计算位或找到最右边|最左边的位的高效按位运算

[英]Efficient bitwise operations for counting bits or find the right|left most ones

Given an unsigned int, I have to implement the following operations:给定一个 unsigned int,我必须执行以下操作:

  1. Count the number of bits set to 1计算设置为 1 的位数
  2. Find the index of the left-most 1 bit找到最左边1位的索引
  3. Find the index of the righ-most 1 bit找到最右1位的索引

(the operation should not be architecture dependents). (该操作不应依赖于体系结构)。

I've done this using bitwise shift, but I have to iterate through almost all the bits(es.32).我已经使用位移位完成了此操作,但我必须遍历几乎所有位(es.32)。 For example, counting 1's:例如,计算 1:

unsigned int number= ...;
while(number != 0){
    if ((number & 0x01) != 0)
        ++count;
    number >>=1;
}

The others operation are similar.其他操作类似。

So my question is: is there any faster way to do that?所以我的问题是:有没有更快的方法来做到这一点?

If you want the fastest way, you will need to use non-portable methods.如果您想要最快的方式,您将需要使用不可移植的方法。

Windows/MSVC:视窗/MSVC:

GCC:海湾合作委员会:

These typically map directly to native hardware instructions.这些通常直接映射到本机硬件指令。 So it doesn't get much faster than these.所以它不会比这些更快。

But since there's no C/C++ functionality for them, they're only accessible via compiler intrinsics.但是由于它们没有 C/C++ 功能,因此只能通过编译器内部函数访问它们。

Take a look at ffs(3), ffsl(3), fls(3), flsl(3).看看 ffs(3), ffsl(3), fls(3), flsl(3)。

The ffs() and ffsl() functions find the first bit set (beginning with the least significant bit) in i and return the index of that bit. ffs() 和 ffsl() 函数查找 i 中的第一个位集(从最低有效位开始)并返回该位的索引。

The fls() and flsl() functions find the last bit set in i and return the index of that bit. fls() 和 flsl() 函数查找 i 中设置的最后一位并返回该位的索引。

You might be interested in bitstring(3), too.您可能也对 bitstring(3) 感兴趣。

Quoting from http://graphics.stanford.edu/~seander/bithacks.html引自http://graphics.stanford.edu/~seander/bithacks.html

The best method for counting bits in a 32-bit integer v is the following:对 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

The best bit counting method takes only 12 operations, which is the same as the lookup-table method, but avoids the memory and potential cache misses of a table.最好的位计数方法只需要 12 次操作,这与查找表方法相同,但避免了表的内存和潜在的缓存未命中。 It is a hybrid between the purely parallel method above and the earlier methods using multiplies (in the section on counting bits with 64-bit instructions), though it doesn't use 64-bit instructions.它是上述纯并行方法和早期使用乘法的方法(在使用 64 位指令计算位的部分)之间的混合,尽管它不使用 64 位指令。 The counts of bits set in the bytes is done in parallel, and the sum total of the bits set in the bytes is computed by multiplying by 0x1010101 and shifting right 24 bits.字节中设置的位计数是并行完成的,字节中设置的位的总和是通过乘以 0x1010101 并右移 24 位来计算的。

"The righ-most 1 bit" of number x is given by数字 x 的“最右边的 1 位”由下式给出

pos(1st '1') = log_2(x XOR (x-1) + 1) - 1

Eg:例如:

x               = 1100101000;
x-1             = 1100100111;
x XOR (x-1)     = 0000001111;
x XOR (x-1) + 1 = 0000010000;

The base2-log of the last line then gives you the correct position + 1. So substract 1 from the log-result and you'll have the most-right '1' bit.最后一行的 base2-log 为您提供正确的位置 + 1。因此,从 log-result 中减去 1,您将获得最正确的“1”位。

For the most-right '0' bit you may use对于最右边的“0”位,您可以使用

pos(1st '0') = log_2(x XOR (x+1) + 1) - 1

With C++20, these operations can be done easily with the newly added header, <bit> .在 C++20 中,这些操作可以通过新添加的 header, <bit>轻松完成。

  1. popcount
  2. countl_one
  3. countr_one

Each of them would then call compiler specific functions like __popcnt() and __builtin_popcount() .然后他们每个人都会调用编译器特定的函数,如__popcnt()__builtin_popcount()

One approach is to use a lookup-table. 一种方法是使用查找表。

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]];
}

for rightmost bit simple ans对于最右边的简单答案

First Method第一种方法

unsigned int getFirstSetBit(int n){

return log2(n & -n) + 1; 

} }

Second Method第二种方法

unsigned int getFirstSetBit(int n){

return ffs(n);   

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM