简体   繁体   English

数值微分:错误的行为不符合预期

[英]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)关于xy

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM