[英]Numerical differentiation: Error does not behave as expected
I want to differentiate a function f(x, y)
with respect to x
and y
numerically using the difference quotient我想使用差商在数字上区分 function
f(x, y)
关于x
和y
def dfdx_v2(x, y, h):
return 0.5 * (f(x+h, y) - f(x-h, y)) / h
def dfdy_v2(x, y, h):
return 0.5 * (f(x, y+h) - f(x, y-h)) / h
where h
is the length of the interval.其中
h
是区间的长度。 In my assumption, the implementation above should be more and more accurate the smaller h
gets.在我的假设中,上面的实现应该越小
h
越准确。 However, I noticed that this is not the case.但是,我注意到情况并非如此。 When I plot the error for
h = [1e-12, 1e-4]
I get the following graph:当我 plot 出现
h = [1e-12, 1e-4]
的错误时,我得到下图:
I would have expected, that the error gets smaller and smaller if I let h
go to zero.我会预料到,如果我让
h
go 为零,误差会越来越小。 However, for very small h
the error increases substantially.但是,对于非常小的
h
,误差会大大增加。 Another interesting observation is that area where the error oscillates very strongly.另一个有趣的观察是误差波动非常强烈的区域。 Why does that happen?
为什么会这样? I would have expected, that the error is a monotonic increasing function without any fluctuations.
我本来预计,该错误是一个单调增加的 function 没有任何波动。 Are there any ideas why the error behaves this way?
有什么想法为什么错误会以这种方式表现?
Here is the code that I used to produce the graph above:这是我用来生成上图的代码:
import numpy as np
import matplotlib.pyplot as plt
def f(x, y):
return x * x + y * x + x * y**2 + np.exp(x) + np.sin(x) * np.cos(x) + np.sin(y)
def dfdx_v1(x, y):
return 2 * x + y + y**2 + np.exp(x) + np.cos(x)**2 - np.sin(x)**2
def dfdy_v1(x, y):
return x + 2 * x * y + np.cos(y)
def dfdx_v2(x, y, h):
return 0.5 * (f(x+h, y) - f(x-h, y)) / h
def dfdy_v2(x, y, h):
return 0.5 * (f(x, y+h) - f(x, y-h)) / h
def main():
x = 2.1415
y = -1.1415
h_min = 1e-12
h_max = 1e-4
n_steps = 10000
h = np.linspace(h_min, h_max, n_steps)
error = list()
for i in range(n_steps):
error.append(np.sqrt((dfdx_v1(x, y) - dfdx_v2(x, y, h[i]))**2 + (dfdx_v1(x, y) - dfdx_v2(x, y, h[i]))**2))
plt.plot(h, error, linewidth=0.2, label="Error")
plt.yscale("log")
plt.legend()
plt.show()
if __name__ == "__main__":
main()
The fact that the error isn't monotonically increasing is a known problem of numerical differentiation.误差不是单调增加的事实是数值微分的一个已知问题。 See this link .
请参阅此链接。
Basically, when step h
becomes too small, expressions such as f(x+h, y) - f(xh, y)
are not computed correctly due to the presence of numerical errors.基本上,当步长
h
变得太小时,诸如f(x+h, y) - f(xh, y)
之类的表达式由于存在数值错误而无法正确计算。 This happens because computers work in finite-precision arithmetic and, therefore, compute f(x+h, y)
and f(xh, y)
with a small error.发生这种情况是因为计算机以有限精度算术工作,因此计算
f(x+h, y)
和f(xh, y)
时误差很小。 Subtracting two very close numbers, which f(x+h, y)
and f(xh, y)
are for small enough h
, usually gives a result dominated by error.减去两个非常接近的数字,即
f(x+h, y)
和f(xh, y)
对于足够小的h
而言,通常会得到以错误为主的结果。 Dividing by h
won't correct the existing error.除以
h
不会纠正现有的错误。
This has to do with the precision of float
s in Python (or most any other programming language).这与 Python(或大多数其他编程语言)中
float
的精度有关。 What happens when h
tends to zero, is that the difference between f(x, y+h)
and f(x, yh)
also tends to zero - however, the latter will not be equaly smooth.当
h
趋于零时, f(x, y+h)
和f(x, yh)
之间的差异也趋于零 - 但是,后者不会同样平滑。 Depending on the exact value of the parameters, the difference will sometimes be (a tiny bit) larger and sometimes a smaller.根据参数的确切值,差异有时会(一点点)更大,有时会更小。
The error in dfdy_v2
will be bigger than in h
due to the numbers being bigger.由于数字更大,
dfdy_v2
中的错误将大于h
中的错误。 Thus the exponent of the error will be bigger.因此误差的指数会更大。 This will both lead to the rippling, due to the quantification of
f
and the strictly increasing error, when h
is approaching zero.由于
f
的量化和严格增加的误差,当h
接近零时,这都会导致波动。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.