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
答案 0 :(得分:1)
如果6个有效十进制数字足够你,exp(x)-1
可以达到x为1e-10。通常,当x约为10**(-N)
时,您将丢失N个十进制数字的精度。我们从大约16位双精度开始。
为什么不总是使用expm1
?因为expm1(x) + 1
绝对没有exp(x)
的优势,所以无论x
有多小。当您的计算实际需要expm1
之类的东西时,使用exp(x) - 1
才有意义。人们必须考虑更广泛的计算背景。
它并不是关于x有多小,而是关于如何在计算中使用exp(x)
。我应该在Loss of significance的更广泛背景下理解expm1
的目的。某些公式在某些参数范围内会失去重要性;一个人必须分析公式,看看它是否以及何时发生。如果在某个范围内存在潜在的重要性损失,请将公式重新修改为代数相等但数值稳定的代数。维基百科在二次方程的例子中很好地解释了这一点。
如果您的目标是计算exp(x)
或3*exp(x) + 4
等,则应使用exp
。这里没有重要意义,无论将expm1
置于这样的公式中都没有任何好处,无论x
有多小。写expm1(x) + 1
而不是exp(x)
完全没有意义。
如果您的公式为exp(x) - 1
或exp(x) - cos(x)
,那么小x
可能会失去重要性。这并不总是重写的理由;如果您只计划在x为1或更大时使用此公式,则没有问题。如果您可以使用绝对错误处于机器epsilon级别(1e-16左右),并且不关心相对错误,则没有问题。
当失去意义时,由信息的最终用户决定可以接受多少损失。通常,获得6位有效数字对于实际目的而言是足够的,因此从双精度精度中丢失10位小数可能是可接受的。在这种情况下,当exp(x) - 1
小于x
时,公式1e-10
会导致不可接受的精度损失。实际上,exp(x) - 1
的值接近x
,但exp(x)
看起来像1.00000000 ...在点为0后有10位数;所以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
根本没有任何好处;我们必须考虑整个计算,以消除几乎相等的数字的减法。