【问题标题】:Efficient bitwise operations for counting bits or find the right|left most ones用于计数位或找到最右边|最左边的高效按位运算
【发布时间】:2012-02-23 23:39:15
【问题描述】:

给定一个无符号整数,我必须执行以下操作:

  1. 计算设置为 1 的位数
  2. 找到最左边1位的索引
  3. 查找最右边 1 位的索引

(操作不应依赖于架构)。

我已经使用按位移位完成了此操作,但我必须遍历几乎所有位(es.32)。 例如,计数 1:

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

其他操作类似

所以我的问题是:有没有更快的方法来做到这一点?

【问题讨论】:

标签: c++ c binary bit-manipulation bits


【解决方案1】:

如果你想要最快的方式,你将需要使用不可移植的方法。

Windows/MSVC:

GCC:

这些通常直接映射到本机硬件指令。所以它不会比这些更快。

但由于它们没有 C/C++ 功能,它们只能通过编译器内部函数访问。

【讨论】:

  • 这与平台无关。
【解决方案2】:

看看 ffs(3)、ffsl(3)、fls(3)、fsl(3)。

ffs() 和 ffsl() 函数查找 i 中的第一个位集(从最低有效位开始)并返回该位的索引。

fls() 和 flsl() 函数查找 i 中设置的最后一位并返回该位的索引。

您可能也对 bitstring(3) 感兴趣。

【讨论】:

    【解决方案3】:

    引用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 位来计算。

    【讨论】:

      【解决方案4】:

      数字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。所以从 log-result 中减去 1,你将得到最右边的 '1' 位。

      对于最右边的“0”位,您可以使用

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

      【讨论】:

        【解决方案5】:

        最右边的简单答案

        第一种方法

        unsigned int getFirstSetBit(int n){
        
        return log2(n & -n) + 1; 
        

        }

        第二种方法

        unsigned int getFirstSetBit(int n){
        
        return ffs(n);   
        

        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-21
          • 1970-01-01
          • 1970-01-01
          • 2019-11-20
          • 2015-04-07
          • 1970-01-01
          相关资源
          最近更新 更多