用電腦算極限

這裡我們要介紹如何用電腦算極限, 以及我們來看一下當我們真的這樣做的時候有可能會發生什麼問題. 我們以 $sinc$ 函數為例來做說明.

sinc function

首先我們要介紹一個特別的函數, $sinc(x)$, 定義如下: $$ sinc(x) = \frac{\sin(x)}{x}, \quad x\ne 0. $$ 很明顯可以看出來當 $x=0$ 的時候分母會等於零, 是一件壞事, 所以把 $x=0$ 這個點先拿掉.

比較有趣的是我們可以把這個函數畫出來. 首先我們在 $[-20, 20]$ 這個區間取 $1000$ 個點, 然後帶入上面 $sinc$ 函數的定義, 再把所有點連起來看看.

Remark: 有件事需要先說明一下, 由於我們是在 $[-20, 20]$ 這個區間均勻的取偶數個點, 所以會有 $500$ 個正數以及 $500$ 個負數, 重點是保證不會取到 $x=0$ 這個點, 所以沒有問題. 相反的, 如果取奇數個點就一定會取到 $x=0$, 那就會有函數無定義的問題了.

我們很輕易可以看出來, 連起來的線還蠻"光滑"的. 函數值在 $x=0$ 附近似乎不會趨近正無窮大或負無窮大, 也沒有跳躍的現象. 接著我們試著在 $x=0$ 附近放大一點看看, 我們在 $[-0.1, 0.1]$ 這個區間取 $1000$ 個點, 然後帶入 $sinc$ 函數的定義再把它畫出來:

看起來真的很光滑!! 而且似乎當 $x$ 很靠近 $0$ 時, $sinc(x)$ 的值很靠近 $1$.

接著我們取一個會越來越靠近 $0$ 的數列, 然後看一下當把 $sinc$ 函數在這個數列的點上取值時, 其值會不會越來越靠近 $1$. 我們取以下數列:

 1.670170079024566e-5
 6.14421235332821e-6
 2.2603294069810542e-6
 8.315287191035679e-7
 3.059023205018258e-7
 1.1253517471925912e-7
 4.139937718785167e-8
 1.522997974471263e-8
 5.602796437537268e-9
 2.061153622438558e-9

算一下 $sinc$ 函數在這些點上面的值, 並觀察他的趨勢:

 0.9999999999535089
 0.9999999999937081
 0.9999999999991485
 0.9999999999998848
 0.9999999999999845
 0.9999999999999979
 0.9999999999999997
 1.0
 1.0
 1.0

赫然發現算到後來就等於 $1$ 了!! 所以我們發現

$$ \lim_{x\to 0} sinc(x) = \lim_{x\to 0} \frac{\sin(x)}{x} = 1. $$

不過有一點點詭異的是, 在剛剛的計算裡我們最多也只是取到離 $0$ 很近的點而已, 但是算出來的結果卻是 $1$. 難道不只是 $sinc(0)=1$, 我們也有 $sinc(2.061153622438558 *10^{-9})=1$ 嗎?

事實上並不是這樣. 電腦有所謂的捨入誤差(rounding error). 這是因為電腦需要用有限位數來表達無窮小數, 所以一定要捨棄後面的位數. 我們把算出來的數字減去 $1$ 看看:

 -4.649114426769074e-11
 -6.291855925155687e-12
 -8.515410598874951e-13
 -1.1524114995609125e-13
 -1.554312234475219e-14
 -2.1094237467877974e-15
 -3.3306690738754696e-16
  0.0
  0.0
  0.0

我們可以發現這個數字最小可以到大約 $10^{-16}$, 之後就變成 $0$ 了. 也就是說我們目前用個這個程式語言其捨入誤差大約就是 $10^{-16}$.


machine epsilon

一般我們會用 machine epsilon 這個數字來量化在電腦裡浮點運算的捨入誤差.

machine epsilon 的定義是, 考慮正數$\epsilon$, 使得 $ 1+ \epsilon \ge 1$ 中最小的那個稱之為 machine epsilon. 當然以數學來看這個 machine epsilon 必須等於零. 不過在電腦裡並不是這樣.

為了方便我們稍微改一下定義, 我們考慮 $\epsilon = 2^{-k}$ 這種形式, 然後 machine epsilon 一樣是使得 $ 1+ \epsilon \ge 1$ 中最小的那個. julia 程式如下:

s=1.0
for k=1:100
    s = s/2.0
    if (1.0+s)<=1.0
        s = 2.0*s
        println("k=", k-1, ",  eps=", s)
        return
    end
end

在我的電腦上我發現 $\epsilon = 2^{-52} = 2.220446049250313e-16$.

k=52,  eps=2.220446049250313e-16

所以的確捨入誤差大約是 $10^{-16}$ 這個等級.


Summary:

稍微總結一下目前我們看到的:

  • 我們用程式跑數值發現 $sinc(x\to 0)=1$, 所以我們可以定義 sinc 函數為 $$ sinc(x) = \begin{cases} \frac{\sin(x)}{x}, \quad x\ne 0, \\\
    1, \quad x=0. \end{cases} $$ 在這樣的定義之下 $sinc$ 函數是個連續函數.

    • 更多關於 $sinc$ 函數的性質可以參考 wiki 上的介紹.
  • 在數值計算上有所謂的捨入誤差, 這是用有限位元來表達無限位數一定會有的差異.

  • 可以用 machines epsilon 來量化捨入誤差.


Avatar
Te-Sheng Lin (林得勝)
Associate Professor

The focus of my research is concerned with the development of analytical and computational tools, and further to communicate with scientists from other disciplines to solve engineering problems in practice.

Related