expm1“函数避免了直接评估小 x 的 exp(x)-1 所涉及的精度损失。”

关于什么是小,是否有经验法则? 1e-1, 1e-10, 1e-100 ?
(边问:是否有性能或其他原因不总是使用 expm1?)

np.info(np.expm1)
Examples
--------
The true value of ``exp(1e-10) - 1`` is ``1.00000000005e-10`` to
about 32 significant digits. This example shows the superiority of
expm1 in this case.

>>> np.expm1(1e-10)
1.00000000005e-10
>>> np.exp(1e-10) - 1
1.000000082740371e-10

最佳答案

简答

如果 6 个有效十进制数字对您来说足够了,那么 exp(x)-1 就可以了,直到 x 为 1e-10。通常,当 x 大约为 10**(-N) 时,您将失去 N 个十进制数字的精度。我们从大约 16 位 double 数字开始。

为什么不总是使用 expm1 ?因为 expm1(x) + 1 绝对没有 exp(x) 的优势,无论 x 有多小。只有当您的计算实际上需要类似 expm1 的东西时,才使用 exp(x) - 1 才有意义。人们必须考虑计算的更广泛的背景。

长答案

这并不是关于 x 有多小,而是关于如何在计算中使用 exp(x)expm1 的目的应该在更广泛的 Loss of significance 上下文中理解。某些公式在某些参数范围内会失去显着性;人们必须分析公式,看看它是否发生以及何时发生。如果在某个范围内存在潜在的显着性损失,请将公式改写为代数等效但数值稳定的公式。维基百科在二次方程的例子中很好地解释了这一点。

如果您的目标是计算 exp(x)3*exp(x) + 4 等,则应使用 exp 。无论 expm1 有多小,这里都不会失去意义,将 x 放入这样的公式中也没有任何好处。编写 expm1(x) + 1 而不是 exp(x) 完全没有意义。

如果您的公式是 exp(x) - 1exp(x) - cos(x) ,那么小 x 可能会失去意义。这并不总是重写的理由;如果您只打算在 x 为 1 或更大时使用此公式,则没有问题。如果您对机器 epsilon 级别(1e-16 左右)的绝对误差没问题,并且不太关心相对误差,则没有问题。

当发生显着性损失时,由信息的最终用户决定可以接受多少损失。通常,获得 6 个有效数字对于实际用途来说已经足够了,因此在 double 精度中丢失 10 个十进制数字可能是可以接受的。在这种情况下,当 exp(x) - 1 小于 x 时,公式 1e-10 会导致无法接受的精度损失。确实,exp(x) - 1 的值接近 x,但 exp(x) 看起来像 1.00000000... 点后 10 位为 0;所以 x 本身只剩下 6 位数字。

以更安全的数值形式重写函数需要一些人力,以计算出所需的任何代数或三角恒等式。这种重写的例子:

f = lambda x: np.exp(x) - np.cos(x)
g = lambda x: np.sqrt(x**2 + 1) - 1

以上数字更安全的形式:
f_safe = lambda x: np.expm1(x) + 2*np.sin(x/2)**2
g_safe = lambda x: x / (np.sqrt(x**2 + 1) + 1)

np.exp(x) - np.cos(x) 重写为 np.expmp(x) - np.cos(x) + 1 根本没有任何好处;人们必须仔细考虑整个计算以消除几乎相等的数字的减法。

关于python - 何时使用 python 函数 expm1 而不是 exp-1,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47725508/

10-11 07:47