两个版本的导数计算之间的精度差异是什么?

What's the accuracy difference between the two versions derivative calculation?

提问人:GabrielChu 提问时间:12/3/2016 最后编辑:GabrielChu 更新时间:12/19/2016 访问量:215

问:

以下是旨在计算给定函数导数的Python代码。f

  1. 版本 1(解决方案)

    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
    
  2. 版本二(我的版本)

    fx = f(x) # evalute f(x)
    x[ix] += h 
    fxh = f(x) # evalute f(x+h)
    x[ix] -= h
    numgrad = (fxh - fx) / h
    

它表明版本一提供了更好的准确性,谁能解释一下为什么会这样,两种计算之间有什么区别?

更新我一开始没有意识到这是一个数学问题,我以为这是一个与浮动精度影响有关的问题。正如MSeifert所建议的,我确实同意浮点噪声很重要,当暴露于噪声时,小幅度的结果更容易受到影响。

python 算法 浮动精度

评论

0赞 D.W. 12/3/2016
欢迎来到 CS.SE!一般来说,代码在这里是题外话,任何特定于 Python 的东西在这里都是题外话。编码问题经常可以在 Stack Overflow 上提出;如果您希望将您的问题移到那里,请单击“标记”以标记此内容以引起版主的注意,并要求模组将其迁移。或者,如果这不是特定于 Python 的,请将代码替换为数学或伪代码,即使是不了解 Python 的人也能理解。(例如:我知道一些 Python,但我不知道在这种情况下是什么意思。x[ix]
0赞 Phillip 12/19/2016
请注意,第一个版本提供更好准确性的说法通常不正确。在某些情况下,单侧近似在数学上是有利的(即,独立于计算机的浮点运算)。例如,参见逆风方案。要解释为什么第一个版本在大多数时候更准确,请熟悉有限差分的顺序

答:

0赞 MSeifert 12/19/2016 #1

你的解决方案是“片面的”,你比较,一般的解决方案是“双面的”。f(x+h) - f(x)f(x+h) - f(x-h)

知道什么就好了

它表明版本一提供了更好的准确性

方法。因为这太笼统了。

但我想我有一个例子,在这里可能很合适:

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)

请注意,双面结果更接近预期值。这甚至可能导致灾难性的取消。然后,您最终可能会得到一个主要由浮点噪声控制的结果。这种效果进一步增强,因为该值除以一个非常小的数字。

通过使用两边,您可以增加(取决于您的功能!)差异,从而增加可能发生取消的点。但在我看来,最大的优势是你把两侧的斜率都考虑在内(稍微平均一下)。例如:

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)

这比单侧近似更接近真实值(两个数量级)。

评论

0赞 Phillip 12/19/2016
我想说最大的优点是第一个版本的错误在,而另一个版本的错误在.O(h²)O(h)
0赞 MSeifert 12/19/2016
@Phillip我想说这取决于功能。我主要关注浮点方面(它标有浮点精度)。还是浮点运算的结果?O(h**2)
0赞 Phillip 12/19/2016
它是一个数学结果,适用于存在一阶导数和二阶导数的所有函数,它是数学对象上的一个,而不是它们在计算机中的表示。
0赞 MSeifert 12/19/2016
是的,我知道。我只是感到困惑,因为你的原始评论模棱两可。在这种情况下,错误可能意味着任何事情。感谢您的澄清。
3赞 Serge Ballesta 12/19/2016 #2

这不是一个 Python 问题,而是一个纯粹的算法问题。假设函数 f 具有很好的性质,您可以查看它的泰勒级数发展:

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 中的项已下降,误差为 h2 的大小级

当然,只有当所需的衍生品存在时,它才有意义......