我使用以下代码计算一阶导数:
enter code here
例如,对于def f(x):
f = np.exp(x)
return f
def dfdx(x):
Df = (f(x+h)-f(x-h)) / (2*h)
return Df
,它可以正常工作。但是,当我将x == 10
设置为h
或以下时,10E-14
开始
以获得与期望值Df
确实相距甚远的值,并且期望值与f(10)
之间的相对误差变得很大。
那是为什么?这是怎么回事?
答案 0 :(得分:3)
对f(x)
的评估最多具有|f(x)|*mu
的舍入误差,其中mu
是浮点类型的机器常数。因此,中心差公式的总误差约为
2*|f(x)|*mu/(2*h) + |f'''(x)|/6 * h^2
在当前情况下,指数函数等于其所有导数,因此误差与
成比例mu/h + h^2/6
的最小值为h = (3*mu)^(1/3)
,对于带有mu=1e-16
的双精度格式,最小值为h=1e-5
。
如果在分母中使用评估点之间的实际差值2*h
代替(x+h)-(x-h)
,则会提高精度。在下面到精确导数的距离的对数图中可以看到这一点。
答案 1 :(得分:2)
您可能会遇到一些数值不稳定的情况,例如对于x = 10和h =〜1E-13,无论加还是减去h,np.exp的参数都非常接近10,因此的近似误差很小np.exp通过除以2 * h的小数来显着缩放。
答案 2 :(得分:2)
除了@LutzL的答案之外,我还将在5.7章的出色著作Numerical Recipes 3rd Edition: The Art of Scientific Computing中添加一些有关数值导数的信息,尤其是关于给定h
的最佳x
值:
h
,以使h
和x
相差一个可精确表示的数字。除非1/3
等于x
的东西,否则应避免使用诸如14.3333333
之类的有趣东西。epsilon * |f(x) * h|
,其中epsilon为浮点精度,Python表示浮点数具有双精度,因此为1e-16
。对于更复杂的功能(可能会进一步导致精度错误),它可能会有所不同,尽管情况并非如此。h
:如果您的sqrt(epsilon) * x
接近零(除非您在书中会找到更多信息),否则不作任何详细介绍就简单的正向情况而言x
,这是您的情况。在这种情况下,您可能希望使用更高的x
值,已经提供了补充答案。在您的示例中,f(x+h) - f(x-h)
等于epsilon ** 1/3 * x
,大约是5e-6
倍x
的情况下,对于较小的值(例如,你的。不过,与@LutzL发布的实际结果相当接近(如果可以这样说的话,请记住浮点运算...)。symmetric
以外,您还可以使用其他派生公式。您可能需要使用forward
或backward
评估(如果函数的评估成本很高,并且您已经预先计算了f(x)
。如果函数的评估成本很低,则可能需要评估多次使用高阶方法来减小精度误差(请参见问题注释中的five-point stencil on wikipedia)。答案 3 :(得分:0)
此Python tutorial解释了精度受限的原因。总之,小数最终以二进制表示,精度约为17个有效数字。因此,在10E-14之后它变得模糊是正确的。