两个版本的导数计算精度有什么区别?
What's the accuracy difference between the two versions derivative calculation?
以下是Python代码,旨在计算给定函数f
的导数。
版本一(解决方案)
x[ix] += h # increment by h
fxh = f(x) # evalute f(x + h)
x[ix] -= 2 * h
fxnh = f(x)
x[ix] += h
numgrad = (fxh - fxnh) / 2 / h
版本二(我的版本)
fx = f(x) # evalute f(x)
x[ix] += h
fxh = f(x) # evalute f(x+h)
x[ix] -= h
numgrad = (fxh - fx) / h
它表明版本一给出了更好的准确性,谁能解释为什么会这样,两种计算有什么区别?
更新
我一开始没有意识到这是一个数学问题,我认为这是一个与浮动精度影响有关的问题。正如 MSeifert 所建议的,我同意浮点噪声很重要,当暴露在噪声中时,小幅度结果更容易受到影响。
你的解是"one-sided",你比较f(x+h) - f(x)
一般的解是"two-sided"f(x+h) - f(x-h)
.
最好知道是什么
It has shown version one gives a better accuracy
意思是。因为那太笼统了。
但我想我有一个可能适合这里的例子:
def double_sided_derivative(f, x, h):
x_l, x_h = x - h, x + h
return (f(x_h) - f(x_l)) / 2 / h
def one_sided_derivative(f, x, h):
x_h = x + h
return (f(x_h) - f(x)) / h
h = 1e-8
def f(x):
return 1e-6 * x
# difference to real derivate:
double_sided_derivative(f, 10, h) - 1e-6, one_sided_derivative(f, 10, h) - 1e-6
# (6.715496481486314e-14, 1.5185825954029317e-13)
注意双面结果更接近预期值。这甚至可能导致 catastrophic cancellation。然后你可能会得到一个主要由浮点噪声控制的结果。由于该值除以非常小的数字,因此进一步增强了这种效果。
通过使用两侧,您可以增加(取决于您的功能!)差异,从而增加可能发生取消的点。但在我看来,最大的优势是你考虑了两侧的坡度(稍微平均一下)。例如:
h = 1e-6
def f(x):
return 4 + x + 5 * x**2
def fdx(x):
return 1 + 10 * x
x = 10
double_sided_derivative(f, x, h) - fdx(x), one_sided_derivative(f, x, h) - fdx(x)
# (-2.7626811061054468e-08, 4.974594048690051e-06)
这比单边近似更接近真实值(两个数量级)。
这不是 Python 问题,而是一个纯算法问题。假设函数 f 有很好的属性,你可以看看它的 Taylor series 发展:
f(x+h) = f(x) + h f'(x) + h*h/2 f"(x) + h*h*h/6 f'''(x) + o(h3)
原来你的第一个表格给出了错误:
((f(x+h) - f(x)) / h) - f'(x) = h/2 f"(x) + o(h)
这是h的量级误差
如果你使用第二种形式,你会得到:
((f(x+h) - f(x-h)) / 2*h) - f'(x) = h*h/3 f'''(x) + o(h2)
h中的项下降了,误差在h的数量级2
当然,只有存在所需的导数才有意义...
以下是Python代码,旨在计算给定函数f
的导数。
版本一(解决方案)
x[ix] += h # increment by h fxh = f(x) # evalute f(x + h) x[ix] -= 2 * h fxnh = f(x) x[ix] += h numgrad = (fxh - fxnh) / 2 / h
版本二(我的版本)
fx = f(x) # evalute f(x) x[ix] += h fxh = f(x) # evalute f(x+h) x[ix] -= h numgrad = (fxh - fx) / h
它表明版本一给出了更好的准确性,谁能解释为什么会这样,两种计算有什么区别?
更新 我一开始没有意识到这是一个数学问题,我认为这是一个与浮动精度影响有关的问题。正如 MSeifert 所建议的,我同意浮点噪声很重要,当暴露在噪声中时,小幅度结果更容易受到影响。
你的解是"one-sided",你比较f(x+h) - f(x)
一般的解是"two-sided"f(x+h) - f(x-h)
.
最好知道是什么
It has shown version one gives a better accuracy
意思是。因为那太笼统了。
但我想我有一个可能适合这里的例子:
def double_sided_derivative(f, x, h):
x_l, x_h = x - h, x + h
return (f(x_h) - f(x_l)) / 2 / h
def one_sided_derivative(f, x, h):
x_h = x + h
return (f(x_h) - f(x)) / h
h = 1e-8
def f(x):
return 1e-6 * x
# difference to real derivate:
double_sided_derivative(f, 10, h) - 1e-6, one_sided_derivative(f, 10, h) - 1e-6
# (6.715496481486314e-14, 1.5185825954029317e-13)
注意双面结果更接近预期值。这甚至可能导致 catastrophic cancellation。然后你可能会得到一个主要由浮点噪声控制的结果。由于该值除以非常小的数字,因此进一步增强了这种效果。
通过使用两侧,您可以增加(取决于您的功能!)差异,从而增加可能发生取消的点。但在我看来,最大的优势是你考虑了两侧的坡度(稍微平均一下)。例如:
h = 1e-6
def f(x):
return 4 + x + 5 * x**2
def fdx(x):
return 1 + 10 * x
x = 10
double_sided_derivative(f, x, h) - fdx(x), one_sided_derivative(f, x, h) - fdx(x)
# (-2.7626811061054468e-08, 4.974594048690051e-06)
这比单边近似更接近真实值(两个数量级)。
这不是 Python 问题,而是一个纯算法问题。假设函数 f 有很好的属性,你可以看看它的 Taylor series 发展:
f(x+h) = f(x) + h f'(x) + h*h/2 f"(x) + h*h*h/6 f'''(x) + o(h3)
原来你的第一个表格给出了错误:
((f(x+h) - f(x)) / h) - f'(x) = h/2 f"(x) + o(h)
这是h的量级误差
如果你使用第二种形式,你会得到:
((f(x+h) - f(x-h)) / 2*h) - f'(x) = h*h/3 f'''(x) + o(h2)
h中的项下降了,误差在h的数量级2
当然,只有存在所需的导数才有意义...