计算只有位设置的数字的最快方法是哪一个是另一个数字中设置的最高位?

时间:2010-08-04 15:24:39

标签: c++ c

  

可能重复:
  Previous power of 2
  Getting the Leftmost Bit

我想要的是,假设有一个5,即101。我的答案应该是100。对于9,即1001,答案应为1000

4 个答案:

答案 0 :(得分:7)

如果不对必须运行的计算机赋予约束,则不能要求最快序列。例如,某些机器支持称为“计数前导零”的指令,或者具有非常快速地模拟它的方法。如果您可以访问此指令(例如使用gcc),那么您可以编写:

#include <limits.h>
#include <stdint.h>
uint32_t f(uint32_t x) 
{
    return ((uint64_t)1)<<(32-__builtin_clz(x)-1);
}
int main()
{
    printf("=>%d\n",f(5));
    printf("=>%d\n",f(9));
}

f(x)返回你想要的东西(x> = y且y = 2 ** n的y最小)。编译器现在将为目标机器生成最佳代码序列。例如,在编译默认的x86_64体系结构时,f()看起来像这样:

    bsrl    %edi, %edi
    movl    $31, %ecx
    movl    $1, %eax
    xorl    $31, %edi
    subl    %edi, %ecx
    salq    %cl, %rax
    ret

你看,这里没有循环! 7条指令,没有分支。

但是,如果我告诉我的编译器(gcc-4.5)优化我现在正在使用的机器(AMD Phenom-II),那么这就出现在f()中:

    bsrl    %edi, %ecx
    movl    $1, %eax
    salq    %cl, %rax
    ret

这可能是这台机器最快的方法。

编辑: f(0)会导致UB,我已经修复了(和程序集)。另外,uint32_t意味着我可以写出32而不会感到内疚: - )

答案 1 :(得分:6)

来自Hacker's Delight,一个不错的无分支解决方案:

uint32_t flp2 (uint32_t x)
{
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >> 16);
    return x - (x >> 1);
}

这通常需要12条指令。如果你的CPU有“计数前导零”指令,你可以少花钱。

答案 2 :(得分:4)

int input = 5;
std::size_t numBits = 0;
while(input)
{
    input >>= 1;
    numBits++;
}
int output = 1 << (numBits-1);

答案 3 :(得分:1)

这是与位计数有关的任务。 Check this out.

使用2a(这是我最喜欢的算法;不是最快的)可以想出这个:

int highest_bit_mask (unsigned int n)  {
   while (n)  {
      if (n & (n-1)) {
         n &= (n-1) ;
      } else {
         return n;
      }
   }
   return 0;
}

n &= (n-1);的神奇之处在于它从n中移除了最不重要的位。 (推论:n & (n-1)仅在n恰好设置一位时才为假。)算法复杂度取决于输入中设置的位数。

无论如何,请查看链接。这是一个非常有趣和启发性的阅读,可能会给你更多的想法。