哪种算法用于计算 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
仅针对数量非常有限的类型定义:float
、double
和 long double
+ 可转换为 double
的任何 Integral 类型。这样就不需要执行复杂的数学运算了。
目前,它使用内置的__builtin_expf
,可以从源代码中验证。这编译为对我机器上的expf
的调用,这是对来自glibc
的libm
的调用。让我们看看我们在他们的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++ 标准库中的指数函数?的主要内容,如果未能解决你的问题,请参考以下文章
VC++如何使用C++ STL标准模板库中的算法函数(附源码)