cmath 中 exp() 函数的浮点实现是否等同于截断的高阶泰勒级数展开?我们应该记住的一个可能的错误来源是表示答案的位数的有限性
4 回答
cmath 中 exp() 函数的浮点实现是否等同于截断的高阶泰勒级数展开?
相当于?是的。那是因为任何体面的实现exp()
都有一半 ULP(最低精度单位)左右的误差。忽略有限精度算术的问题,人们总是可以构造一个截断的泰勒级数来做同样的事情。
然而,没有一个像样的实现exp()
会使用泰勒展开。那将非常非常慢,并且不会达到所需的准确性。这将是一个彻头彻尾的愚蠢实施。更好的是利用 2 x和 e x之间存在强关系的事实,以及考虑到浮点数的 2 表示的几乎普遍的幂,2 x相当容易计算的事实。
只是一个如何计算 exp (x) 的示例:
如果 x 很大,则结果为 +inf。如果 x 非常小,则结果为 0。
令 k = 圆形 (x / ln 2)。然后 exp (x) = 2^k * exp (x - k ln 2)。2^k 很容易计算。一个小问题是计算 x - k ln 2 没有任何舍入误差。这很简单:让 L1 = ln 2 四舍五入为 35 位,并且 L2 = ln 2 - L1。k 是一个较小的整数,所以 k * L1 没有舍入误差,x - k * L1 也没有;然后我们减去 k * L2,它很小,因此舍入误差很小。
为了更快地做到这一点(没有除法),我们计算 k = round (x * (1 / ln 2))。我们检查 x 是否接近于零,因此不需要整个计算。无论如何,我们现在计算 exp (x),结果在 sqrt (1/2) 和 sqrt (2) 之间。
您可以使用泰勒多项式计算 exp (x)。相反,您可能会使用切比雪夫多项式以低得多的程度最小化截止误差。稍加小心,您可以找到一个截断误差远小于结果最低位的多项式。
它取决于编译器、C 运行时和处理器的实现。然而,计算指数的人不太可能使用泰勒展开,因为存在更好的方法。
根据 glibc,它可以使用自己的实现,在评论中说明了这一点(来自 sysdeps/ieee754/dbl-64/e_exp.c):
/* An ultimate exp routine. Given an IEEE double machine number x */
/* it computes the correctly rounded (to nearest) value of e^x */
或者它可以使用硬件支持的处理器指令进行浮点计算,就像 x86 FPU 一样。在这两种情况下,您都可能得到一个完全精确的正确舍入值。
这取决于您使用的 C 库实现。在过于流行的 glibc 中,它不是。