数值差分

**數值微分**是數值方法中的名詞，是用函數的值及其他已知資訊來估計一函數導數的演算法。

## 有限差分法

最簡單的方式是使用有限差分近似。

簡單的二點估計法是計算經過 (_x_,_f(x)_) 及鄰近點 (_x+h_,_f(x+h)_) 二點形成割線的斜率選擇一個小的數值 _h_，表示 _x_ 的小變化，可以是正值或是負值。其斜率為

　
: ${f(x+h)-f(x) \over h}.$

此表示法是牛頓的差商，也稱為一階均差。

割線斜率和切線斜率有些差異，差異大約和 _h_ 成正比。若 _h_ 近似於 0，則割線斜率近似於切線斜率。因此，函數 **f** 真正在 _x_ 處真正的斜率是割線趨近切線時的差商：

　
: $f'(x)=\lim _{h\to 0}{f(x+h)-f(x) \over h}.$

若直接將 _h_ 用 0 取代會得到除以零的結果，因此計算導數需要一些較不直覺的的方式。

同様的，切線斜率也可以用 (x - h) 和 x 二點的割線斜率近似。

另外一種二點估計法是用經過 (_x-h_,_f(x-h)_) 和 (_x+h_,_f(x+h)_) 二點的割線，其斜率為

　
: ${f(x+h)-f(x-h) \over 2h}.$

上述公式稱為對稱差分，其一次項誤差相消，因此割線斜率和切線斜率的差和 $h^{2}$ 成正比。對於很小的 _h_ 而言這個值比單邊近似還要準確。特別的是公式雖計算 x 點的斜率，但不會用到函數在 x 點的數值。

估計誤差為：

　
: $R={{-f^{(3)}(c)} \over {6}}h^{2}$ ,

其中 $c$ 為在 $x-h$ 和 $x+h$ 之間的某一點。此誤差沒有包括因為有限準確度而產生的捨入誤差。

很多工程計算機都是用對稱差分來計算導數，像德州儀器（TI）的 TI-82、TI-83、TI-84 及 TI-85，其 _h_=0.001。

雖然在實務十分常用，但上述二種方式的數值微分常被研究者批評，尤其是被一些鼓勵使用自動微分的研究者批評，因為上述的數值微分其精確度不高，若計算器精準度是六位數，用對稱差分計算導數只有三位數的精確度，而若是找到一計算斜率的函數，仍可以有幾乎六位數的精確度。例如假設 f (x) = x2，用 2x 計算斜率有幾乎完整的準確度，而用差分近似就會有上述的問題。

### 利用浮點數的實際考量

若計算時使用浮點數，就需要考慮 _h_ 要取到多小。若選的太小，相減之後會有大的捨入誤差，事實上整個有限差分的公式都是病態的，若 _h_ 夠小，導數不為零的情形下，在相消後會得到數值微分為零的結果，若 _h_ 太大，計算割線斜率的結果就會更加準確，但用割線斜率估算切線斜率的誤差就更大了。

一種可以產生夠小的 _h_，但又不會產生捨入誤差的方式是 ${\sqrt {\varepsilon }}x$ （不過 _x_ 不能為 0），其中最小浮點數 _ε_ 大約是 2.2×10−16 數量級。
。以下是一個一個可以平衡捨入誤差和公式誤差，有最佳精確度的 _h_ 為

 $h=2{\sqrt {\varepsilon |{f(x) \over f''(x)}|}}$ （不過 f"(x) = 0 時不成立），而且需要有關函數的資訊。

上述的最小浮點數是針對雙精度（64-bit）變數，單精度變數在這類計算幾乎不太實用。其計算結果在二進制中不太可能是「整數」。雖然 _x_ 是可以用浮點數表示的數字，但 _x_ + _h_ 幾乎不會也是可用浮點數表示（而且和 _x_ 不同）的數字，因此 _x_ + _h_ 需調整為機器可讀的數字，因此會出現 (_x_ + _h_) - _x_**不等於**_h_ 的情形，因此用二個函數計算值計算微分時，二個位置的差不會是 _h_。幾乎所有的十進制分數在二進制下都會是循環小數（都像 1/3 在十進制中的情形一様），例如 _h_ = 0.1 在二進制下會是循環小數，是 0.000110011001100...。因此在浮點數下一個可能計算的方式是：

```
 h:=sqrt(eps)*x;
 xph:=x + h;
 dx:=xph - x;
 slope:=(F(xph) - F(x))/dx;
```

先計算 (_x_ + _h_) - _x_ 的值，再用這個值作為微分算式的分母，不過若是用電腦計算，編譯器最佳化的機能可能會認為 _dx_ 和 _h_ 相同，因此讓上述的方式失效。若是用 C 或其他類似的程式語言，可以讓 _xph_ 宣告成 Volatile 變數，以避免此一問題。

### 高階方法

也有用更高階估計導數的方法，或是估計高階導數的方法。

以下就是一階導數的五點法（一維下的五點模版）

　
: $f'(x)={\frac {-f(x+2h)+8f(x+h)-8f(x-h)+f(x-2h)}{12h}}+{\frac {h^{4}}{30}}f^{(5)}(c)$

其中 $c\in [x-2h,x+2h]$ .

## 微分求積

微分求積（Differential quadrature）是用函數在特定位置數值的加權和來近似導數，其名稱類似數值積分中用的求積（quadrature），也就是像梯形法或是辛普森法中用的加權和，有許多方式可找出加權的係數，在求解偏微分方程式時會用到微分求積。

## 複變的方法

傳統用有限差分近似數值微分的方式是病態的，不過若 $f$ 是全純函數，在實數軸上的值都是實數，可以用複數平面中靠近 $x$ 的位置來求值，此方式為數值穩定的方式，例如一階導數可以用以下的複數導數公式計算：

　
: $f'(x)\approx \Im (f(x+ih))/h$ .

上述公式只在計一階導數時有效，若要拓展到任意階導數，需要用到多重複數，結果也會是多重複數的導數。

而任意階的導數可以用柯西積分公式計算：

　
: $f^{(n)}(a)={n! \over 2\pi i}\oint _{\gamma }{f(z) \over (z-a)^{n+1}}\,\mathrm {d} z$ ,

其中積分會用數值積分計算。

Lyness 和 Moler 在 1967 年提出用複變數來計算數值微分。Abate 和 Dubner 提出一種用複數拉普拉斯轉換的數值反演為基礎的算法。

## 參考資料

## 相關條目

* 自動微分
* 差分
* 五點模板
* 數值積分
* 數值常微分方程式
* Savitzky–Golay 濾波器
* 數值分析軟體列表

## 外部連結

* http://mathworld.wolfram.com/NumericalDifferentiation.html （頁面存檔備份，存於網際網路檔案館）
* https://web.archive.org/web/20130820223117/http://math.fullerton.edu/mathews/n2003/NumericalDiffMod.html
* Numerical Differentiation Resources: Textbook notes, PPT, Worksheets, Audiovisual YouTube Lectures at Numerical Methods for STEM Undergraduate
* ftp://math.nist.gov/pub/repository/diff/src/DIFF Fortran code for the numerical differentiation of a function using Neville's process to extrapolate from a sequence of simple polynomial approximations.
* NAG Library numerical differentiation routines （頁面存檔備份，存於網際網路檔案館）
* http://graphulator.com （頁面存檔備份，存於網際網路檔案館） Online numerical graphing calculator with calculus function. （頁面存檔備份，存於網際網路檔案館）