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] .