JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

什麼是計算數學?

認識這門用演算法求解實際問題的數學分支:它的答案是刻意且誠實的近似值。你將學會對每個方法都要問的兩個問題:它有多不準?它要花多少代價?

一種不一樣的答案

在你已經爬過的微積分與線性代數裡,答案通常是一個精確的式子:這個積分等於 pi/2,這個方程組的解是 x = 3,這個特徵值恰好是 sqrt(2)。計算數學問的卻是一個更謙卑、更實用的問題:給定一個真實問題與一台有限的機器,我們要如何產生一個夠接近、夠快、而且可以信賴的數字?它是數值分析的家,而它的答案幾乎永遠是近似的——不是因為我們馬虎,而是因為精確答案要不是搆不著,就是根本不需要。

可以這樣想其中的差別。純粹的、符號式的數學像建築師完美的藍圖:紙上有一條精確代表 sqrt(2) 的線。計算數學則是那位木匠,他必須把一塊真實的木板鋸成 1.41421356 公尺,因為沒有任何鋸子能鋸出無窮位的小數。兩者都在做數學;一個活在理想物件的世界,另一個活在有限機器、有限時間與不完美資料的世界。木匠並不是把建築師的工作搞砸了——他做的是建築師根本做不到的工作。

演算法與它的代價

這個領域的核心物件是演算法:一份有限、毫不含糊、把輸入變成輸出的步驟食譜。你在虛擬碼裡已經見過演算法;在這裡它們承載的是數字,而不只是邏輯。一個經典例子是用來解 f(x) = 0 的牛頓法。你猜一個起點 x_0,然後反覆改進它:每個新的猜測,就是 f 在目前猜測處的切線與零相交的地方。

x_{n+1} = x_n - f(x_n)/f'(x_n)

guess x_0
repeat:
    x_{n+1} = x_n - f(x_n)/f'(x_n)
until |x_{n+1} - x_n| is tiny
牛頓法:一個三行的迴圈,逐步磨利對 f 之根的猜測。

一旦你有了演算法,第二個問題永遠是:它要花多少代價?代價以基本運算的次數來衡量,看它如何隨問題規模 n 增長,並以大 O 記法書寫。把 n 個項目排序也許要 O(n log N);用高斯消去法解一個稠密線性方程組 A x = b 約需 O(n^3);而快速傅立葉轉換把一件 O(n^2) 的工作變成 O(N log N),正是這種加速改變了「可能與否」的界線。把花費 O(n^3) 的 n 加倍,工作量就變成八倍——代價不是事後才想的事,它決定了你的方法是今天跑完還是明年跑完。

誤差從哪裡來

如果每個答案都是近似的,那麼理解我們的數字與真相之間的差距,就是這門技藝的核心。那個差距就是誤差,它從四個不同的水龍頭湧入。本級接下來的四篇指南會逐一打開每個水龍頭,但先看清整套管路會很有幫助。

  1. 建模誤差:方程式本身就已經是對現實的簡化。我們把一根真實的樑模型化成一條完美的線,或把空氣當成沒有黏滯性。早在任何電腦碰它之前,模型就已經是錯的。
  2. 資料誤差:輸入是量測來的,而量測帶有雜訊。如果你的起始數字只準到三位,沒有任何演算法能交給你十位可信的數字。
  3. 截斷誤差:我們用有限的過程取代無窮的過程。我們把無窮級數只取前幾項,或用有限差分近似導數。這就是你會一再遇到的 O(h^p) 誤差。
  4. 捨入誤差:機器無法精確儲存大多數實數。它以浮點數運作,只保留約 16 位十進位數字,並在每一個運算都進行捨入。

最後那個水龍頭值得仔細端詳,因為它讓每個人都吃驚。電腦裡的浮點數並不是你課本裡的實數。親切的小數 0.1 沒有精確的二進位形式,所以 0.1 + 0.2 不會剛好得到 0.3。更糟的是,浮點加法不滿足結合律:(a + b) + c 可能不等於 a + (b + c)。這些不是程式錯誤;它們是把無窮的實數線塞進 64 個位元所必須付的誠實代價,而一個好的演算法,正是設計來讓這個代價保持微小。

衡量差距:絕對與相對

要精確地談誤差,我們需要兩把尺。絕對誤差是真值與計算值之間的原始距離——若真值是 100 而我們得到 100.5,絕對誤差就是 0.5。相對誤差則把那個差距除以真值的大小——這裡是 0.5/100,也就是 0.5%。我們通常在意的是相對誤差,因為它告訴我們手上有幾位正確的有效數字,與尺度無關。誤差 0.5 在一百萬旁邊微不足道,在 1 旁邊卻是災難。

這裡是整個本級最深刻的想法,值得一句口號:準確度 = 條件 x 穩定性條件數衡量問題本身有多敏感——當輸入抖動時,答案會抖動多少,不管是誰來解。穩定性則衡量你那個特定演算法額外加進去多少誤差。一個條件數接近 10^8 的問題,會在任何演算法開始之前就先讓你損失約 16 位雙精度數字中的 8 位,純粹因為這問題就是這麼厲害地放大輸入雜訊。一個完美穩定的演算法,在病態問題上照樣吐出垃圾;那是問題的錯,不是方法的錯。

那麼,一個好的演算法到底承諾什麼?並不是你那個確切問題的確切答案——那往往不可能。實際的目標是後向穩定性:演算法回傳的是某個鄰近問題的精確答案,那個問題的輸入與你的輸入只差一個捨入誤差。如果你的問題是良態的,後向穩定的方法會給你一個可信的答案;如果它是病態的,它就誠實地告訴你:沒有任何方法能做得更好。這也是為什麼實務上你很少靠求反矩陣來解 A x = b——那比直接對 A 做分解更貴、也更不穩定。

向答案收斂

許多數值方法不會一擊就完成;它們會迭代,產生一串 x_0, x_1, x_2, ...,你希望這串數字朝著真答案前進。如果這些猜測隨著步數增加而安定到真值,這個方法就收斂。但兩個都收斂的方法,速度可能天差地遠,而收斂率就是我們替這件事打分的方式。線性收斂每一步消掉剩餘誤差的固定比例——想成每次都把差距減半。二次收斂則大致把每一步的誤差平方,所以正確位數每步翻倍:飛快的 2、4、8、16 位。

牛頓法是二次收斂的招牌代表——但,這裡是誠實的小字附註,只有在單根附近、而且起點夠接近時才成立。離根很遠,或在 f'(x) 接近零的平坦處,牛頓法可能劇烈衝過頭、發散,甚至在兩點之間永遠來回振盪。「能用時很快」並不等於「永遠能用」,而整個領域一個反覆出現的教訓是:每個方法都圍著一道籬笆,框住它乖乖聽話的那些情形。

收斂還有第二層你會不斷用到的意思:當你縮小步長 h——有限差分裡的間距、數值積分裡每片的寬度——截斷誤差會像 O(h^p) 那樣縮小,其中指數 p 就是準確度的階。一個二階方法 O(h^2),在你把 h 減半時誤差變成四分之一。人們很容易以為 h 越小答案就越好,但那是個陷阱:h 縮得太小,捨入誤差就會接管,替你能達到的準確度設下一個地板。存在一個甜蜜點,而找到它,恰恰就是你剛剛遇見的截斷與捨入之間的那道平衡。