2016-12-03 43 views
-2

以下是Python代碼,旨在計算給定函數f的導數。兩個版本的派生計算之間的精度差是多少?

  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所建議的那樣,我確實同意浮點噪聲很重要,小的結果在暴露於噪聲時更易受影響。

+0

歡迎CS.SE!一般來說,代碼在這裏是無關緊要的,任何特定於Python的代碼都是無關緊要的。編碼問題通常可以在Stack Overflow上提出;如果您希望在那裏移動您的問題,請點擊「標誌」將此標記爲主持人注意力,並要求模塊遷移它。或者,如果這不是特定於Python的,請將代碼替換爲數學或僞代碼,即使不懂Python的人也可以理解。 (例如:我知道一些Python,但我不知道'x [ix]'在這種情況下意味着什麼。) –

+0

請注意,第一個版本提供更好的準確性的說法通常並非如此。在某些情況下,單側逼近在數學上是有利的(即,獨立於計算機的浮點運算)。參見,例如,[迎風計劃](https://en.wikipedia.org/wiki/Upwind_scheme)。爲了解釋爲什麼第一個版本更準確*大多數時間*,請讓自己熟悉[有限差異](https://en.wikipedia.org/wiki/Finite_difference)的*順序*。 – Phillip

回答

3

這不是一個Python問題,而是一個純粹的algorythmic之一。假設函數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

當然,它纔有意義,如果有需要的衍生品

0

您的解決方案是「單面」,您比較f(x+h) - f(x),一般解決方案是「雙面」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) 

這比單側逼近更接近真實值(兩個數量級)。

+0

我想說的最大的好處是,第一個版本的錯誤在'O(h²)'中,而另一個在'O(h)'中。 – Phillip

+0

@Phillip我會說這取決於功能。我主要關注浮點方面(它被標記爲浮點精度)。或者是「O(h ** 2)」是浮點運算的結果? – MSeifert

+0

這是一個數學結果,適用於存在一階和二階導數的所有函數,它是一個數學對象,而不是它們在計算機中的表示。 – Phillip

相關問題