哪种算法用于计算 GNU C++ 标准库中的指数函数?

Posted

技术标签:

【中文标题】哪种算法用于计算 GNU C++ 标准库中的指数函数?【英文标题】:Which algorithm is used to compute exponential functions the GNU C++ Standard Library? 【发布时间】:2018-10-02 06:08:30 【问题描述】:

请考虑在 C++ numerics 库的标头 cmath 中定义的 std::exp。现在,请考虑 C++ 标准库的实现,例如 libstdc++。

考虑到有多种算法来计算基本函数,例如arithmetic-geometric mean iteration algorithm 计算指数函数和其他三个here;

如果可能的话,您能否说出用于计算libstdc++ 中的指数函数的特定算法?

PS:恐怕我无法确定包含 std::exp 实现的正确 tarball 或理解相关文件内容。

【问题讨论】:

libstdc++ 只是转发到编译器内部__builtin_exp,它的实现会因平台和编译器而异。 __builtin_exp 只是 ::exp 的一个花哨名称,它是在 math.h 中声明的 C 函数。 Gcc 不包含任何 exp 的实现,你想在你的 C 库(例如 glibc)中寻找它。 为您挖掘资源。查看更新的答案 【参考方案1】:

它根本不使用任何复杂的算法。请注意,std::exp 仅针对数量非常有限的类型定义:floatdoublelong double + 可转换为 double 的任何 Integral 类型。这样就不需要执行复杂的数学运算了。

目前,它使用内置的__builtin_expf,可以从源代码中验证。这编译为对我机器上的expf 的调用,这是对来自glibclibm 的调用。让我们看看我们在他们的source code 中发现了什么。当我们搜索expf 时,我们发现它在内部调用__ieee754_expf,这是一个系统相关的实现。 i686 和 x86_64 都只包含一个 glibc/sysdeps/ieee754/flt-32/e_expf.c ,它最终为我们提供了一个实现(为简洁起见,减少了外观 into the sources

它基本上是浮点数的 3 阶多项式逼近:

static inline uint32_t
top12 (float x)

  return asuint (x) >> 20;


float
__expf (float x)

  uint64_t ki, t;
  /* double_t for better performance on targets with FLT_EVAL_METHOD==2.  */
  double_t kd, xd, z, r, r2, y, s;

  xd = (double_t) x;
  // [...] skipping fast under/overflow handling

  /* x*N/Ln2 = k + r with r in [-1/2, 1/2] and int k.  */
  z = InvLn2N * xd;

  /* Round and convert z to int, the result is in [-150*N, 128*N] and
     ideally ties-to-even rule is used, otherwise the magnitude of r
     can be bigger which gives larger approximation error.  */
  kd = roundtoint (z);
  ki = converttoint (z);
  r = z - kd;

  /* exp(x) = 2^(k/N) * 2^(r/N) ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */
  t = T[ki % N];
  t += ki << (52 - EXP2F_TABLE_BITS);
  s = asdouble (t);
  z = C[0] * r + C[1];
  r2 = r * r;
  y = C[2] * r + 1;
  y = z * r2 + y;
  y = y * s;
  return (float) y;

同样,对于 128 位 long double,它是 order 7 approximation,对于 double,他们使用 more complicated algorithm,我现在无法理解。

【讨论】:

您正在查看 x87 指令,这些指令现在仅与 long double 远程相关。如果你看 asm,__builtin_expf 变成了对 expf 的调用(由 C 库提供)。 @MarcGlisse 我尝试让 gcc 内联该调用,但没有成功。 当然没有内联。您多久看到一次代码中内联外部库的函数? 我发现这个答案真的很有帮助!奇怪的是,看起来这不是当前 glibc releases 中使用的实际算法。版本 2.26(最新版本,从 2018 年 2 月 1 日开始)的来源不同 - 请参阅 sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/flt-32/… 。源最近被修改(sourceware.org/git/…),但这个更改似乎还没有通过发布 我在之前的评论中弄错了时间线。 Glibc 2.26 版来自 2017 年 8 月,具有旧算法(与此答案中发布的不同),但 2.27 版(从 2018 年 2 月 1 日开始)使用上述算法。不过,如果您的 glibc 不是最新的,那么您的机器使用的算法可能会有所不同。

以上是关于哪种算法用于计算 GNU C++ 标准库中的指数函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 标准库中更改堆中的最大元素?

VC++如何使用C++ STL标准模板库中的算法函数(附源码)

为啥 C++ 标准库中没有线程池?

为啥 C++ 标准库中没有 SIMD 功能?

c++如何直接调用自己写的类中的函数,就像调用标准库中的函数那样

模拟实现c++标准库和boost库中的智能指针