我想要的是,假设有一个5
,即101
。我的答案应该是100
。对于9
,即1001
,答案应为1000
答案 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
恰好设置一位时才为假。)算法复杂度取决于输入中设置的位数。
无论如何,请查看链接。这是一个非常有趣和启发性的阅读,可能会给你更多的想法。