Algorithm 如何高效地计算楼层日志基数2^(1/4)
计算Algorithm 如何高效地计算楼层日志基数2^(1/4),algorithm,bit-manipulation,numerical-methods,Algorithm,Bit Manipulation,Numerical Methods,计算floor(log_2(x))可以通过计算有快速算法的零的数量来完成 当x是一个覆盖所有可能值的64位无符号整数时,计算floor(log{2^(1/4)}(x))是否有类似的技巧 Log{{ 2 ^(1/4)}(x)=4×Logy2(x)=Log2(x ^ 4)< /代码>,这相当于找到一个高效的算法:地板(4×Log2(x))< /> >或地板(log(x^ 4))< /p> < p> < >代码>地板(Log2(x))< /代码>,我们可以划分 z=x/2 ^楼层(Log2(x))<
floor(log_2(x))
可以通过计算有快速算法的零的数量来完成
当x
是一个覆盖所有可能值的64位无符号整数时,计算floor(log{2^(1/4)}(x))
是否有类似的技巧
Log{{ 2 ^(1/4)}(x)=4×Logy2(x)=Log2(x ^ 4)< /代码>,这相当于找到一个高效的算法:<代码>地板(4×Log2(x))< /> >或<代码>地板(log(x^ 4))< /p> < p> < >代码>地板(Log2(x))< /代码>,我们可以划分<代码> z=x/2 ^楼层(Log2(x))< /代码>并考虑计算<代码>楼层的问题(Logi)<> <代码>{2^(1/4)}(z))其中
z
属于[1,2]
,因为floor(log{2^(1/4)}(x))=4 floor(log_2(x))+floor(log_{2^(1/4)}(z))
只有四种可能性floor(log_{2^(1/4)}(z))
,所以代码的两个比较(三个分支)与(2^(1/4))^1, (2^(1/4))^2, (2^(1/4))^3
就足够了。为了完全避免浮点运算,“除法”可以实现为左移位,将(2^63)z
与类似表示的常量进行比较
现在使用C代码:
#include <assert.h>
#include <stdio.h>
static int mylog(unsigned long long x) {
assert(x > 0ULL);
/* compute n = floor(log2(x)) */
unsigned long long y = x | (x >> 1);
y |= y >> 2;
y |= y >> 4;
y |= y >> 8;
y |= y >> 16;
y |= y >> 32;
y -= (y >> 1) & 0x5555555555555555ULL;
y = (y & 0x3333333333333333ULL) + ((y >> 2) & 0x3333333333333333ULL);
y = (y + (y >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
y = (y + (y >> 8)) & 0x00ff00ff00ff00ffULL;
y = (y + (y >> 16)) & 0x0000ffff0000ffffULL;
y = (y + (y >> 32)) & 0x00000000ffffffffULL;
int n = (int)y - 1;
/* normalize x and use binary search to find the last two bits of the log */
x <<= 63 - n;
n <<= 2;
if (x < 0xb504f333f9de6485ULL) {
return x < 0x9837f0518db8a970ULL ? n : n + 1;
} else {
return x < 0xd744fccad69d6af5ULL ? n + 2 : n + 3;
}
}
int main(void) {
unsigned long long x;
while (scanf("%llu", &x) == 1) {
printf("%d\n", mylog(x));
}
}
loguuu{2^(1/4)}(x)=logu2(x)/logu2(2^(1/4))=logu2(x)/(1/4)=4logu2(x)哦,哎呀,我忘了分母中的2^。抱歉!那太神奇了,谢谢!作为额外的奖励,这实际上比天真的
地板(4*logu2(x))更准确
方法由于大x
的舍入误差。就性能而言,直接转换为Go不会产生我预期的那么大的性能差异。对于随机、均匀分布的uint64值,我正在对原始方法进行基准测试54.7ns/op
,对上述方法进行基准测试19.8ns/op
e> log_2计算部分在7.9ns/op
处单独进行基准测试。
BaseForm[Table[Ceiling[2^(63+i/4)],{i,1,3}],16] .