是否有一种有效的方法来查找数字的log2,假设它是2的幂。我知道显而易见的方法,比如有一张桌子或
for (log2=0;x!=1;x>>=1,log2++);
但我想知道是否有更高效/更优雅的方式。
答案 0 :(得分:11)
您可以只计算前导或尾随零位的数量,因为任何精确的2次幂都表示为单个1位,其他所有位为0.许多CPU都有执行此操作的特殊指令,以及编译器等因为gcc具有这些操作的内在函数,它们被编译为适当体系结构上的单个指令。
如果你有一个有效的clz
(“计数前导零”),那么log2
实现可能如下所示:
int32_t ilog2(uint32_t x)
{
return sizeof(uint32_t) * CHAR_BIT - clz(x) - 1;
}
(注意:ilog2(0)
返回-1。)
使用gcc或兼容gcc的编译器时,您可以像这样定义clz
:
#define clz(x) __builtin_clz(x)
微软有类似的东西:BitScanReverse。
请注意,计算尾随零(使用ctz
指令)似乎更方便,但a clz
instruction is more widely available on different CPU architectures。
使用clz
而非ctz
的另一个好处是,您获得floor(log2(x))
非幂2值,使您的ilog2
函数更加普遍有用比如果你使用ctz
,那只适用于精确的2次幂。
答案 1 :(得分:1)
我没有对此进行基准测试,但它应该运行得相当快,因为它不需要多次迭代:
int which_power_of_2(uint64_t x) {
uint64_t z = 0x0000000100000000ULL;
int p = 31, d = 16;
while (d) {
if (x & (z-1)) {
p -= d;
z >>= d;
}
else {
p += d;
z <<= d;
}
d >>= 1;
}
return x ? ((x & z) ? p+1 : p) : -1;
}