高效 10 倍的功率

Efficient 10 to the power double

我必须多次计算 10 的 2 次方。

有没有比数学库更有效的方法pow(10,double)?如果重要的话,我的双打在-5和-11之间总是负数。

我假设 pow(double,double) 使用比 pow(10,double) 所需的更通用的算法,因此可能不是最快的方法。鉴于下面的一些答案,这可能是一个错误的假设。

至于为什么,是为了对数插值。 我有一个 table 的 x 和 y 值。 我的对象有一个已知的 x 值(几乎总是双精度值)。

double Dbeta(struct Data *diffusion, double per){
  double frac;
  while(per>diffusion->x[i]){
      i++;
  }
  frac = (per-diffusion->x[i-1])/(diffusion->x[i]-diffusion->x[i-1]);
  return pow(10,log10DB[i-1] + frac * (log10DB[i]-log10DB[i-1]));
}

这个函数被调用了很多次。 我被告知要研究分析,所以这是我首先要做的。

我刚刚被告知我可以使用自然对数而不是以 10 为底数,这显然是正确的。 (我的愚蠢有时甚至让我自己感到惊讶。)

用自然对数替换所有内容后,一切运行得都快了一点。通过分析(这是我今天学到的一个新词),我发现我的代码有 39% 花在了 exp 函数上,所以对于那些想知道是否这部分实际上是我的代码瓶颈的人来说,确实是。

对于pow(10.0, n),设置c = log(10.0)应该更快,你可以计算一次,然后使用exp(c*n),这应该比pow(10.0, n)快得多(基本上在内部做同样的事情,除了它会一遍又一遍地计算 log(10.0) 而不是一次)。除此之外,您可能无能为力。

是的,pow 函数很慢(对于那些要求基准测试的人来说,大约是乘法成本的 50 倍)。

  • 通过一些log/exponents技巧,我们可以将 10^x 表示为

    10^x = exp(log(10^x)) = exp(x * log(10)).
    

    所以你可以用exp(x * M_LN10)实现10^x,这应该比pow更有效率。

  • 如果双精度不是关键,请使用函数的浮点版本 expf(或 powf),这应该比双精度版本更有效。

  • 如果粗略精度没问题,预先计算 [-5, -11] 范围内的 table 并使用线性插值快速查找。

一些基准测试(使用 glibc 2.31):

Benchmark                Time
---------------------------------
pow(10, x)               15.54 ns
powf(10, x)               7.18 ns
expf(x * (float)M_LN10)   3.45 ns