從減半到平方:切線的想法
在本級第一篇,二分法給了你一個牢不可破的保證:把根夾住,每一步區間減半,大約每三步多拿到不到一位十進位數。安全,但慢。在第二篇,當映射是個壓縮時,不動點迭代加快了腳步,每步把誤差縮小一個固定倍率——這就是線性收斂,誤差 e_{n+1} 大約等於 C 乘以 e_n,而 C 小於 1。牛頓法如今伸手去拿某種「在性質上」更快的東西,而全部祕密就是一個大膽的近似:在當前猜測附近,把函數假裝成一條直線。
想像曲線 y = f(x),而你當前的猜測 x_n 落在它上頭某處。在那一點畫出切線——那條碰到曲線、且共用其斜率 f'(x_n) 的直線。直線會在某個顯而易見的地方穿過零,而你只要一個輕鬆的步驟就能解出那個交點。牛頓押的注是:切線的零點,會比你出發處更接近曲線的零點。於是你滑到切線的 x 截距,叫它 x_{n+1},然後重複。每一步都把一個困難的非線性方程換成一個簡單的線性方程——再在新位置上問同樣的問題一次。
- 寫出 x_n 處的切線:直線 y = f(x_n) + f'(x_n) * (x - x_n),它碰到曲線並複製那裡的斜率。
- 令 y = 0 並解這個線性方程求 x——把答案叫做 x_{n+1}。代數運算給出牛頓迭代 x_{n+1} = x_n - f(x_n)/f'(x_n)。
- 在新點上計算 f 與 f' 並重複,一旦殘差 |f(x_n)|(或步長)低於容忍度就停止——全程唯一需要的原料就是 f 和它的導數 f'。
「二次收斂」真正的意思
當牛頓法奏效時,它奏效得驚人,靠的就是二次收斂。精確的說法是關於誤差 e_n = x_n - r(到真根 r 的差距)如何縮小:在單根附近,下一個誤差大致正比於當前誤差的平方,e_{n+1} 大約等於 M 乘以 e_n^2,其中 M 是某個常數。把一個小數平方會讓它變得極小:若你的誤差是 0.01,一步後約為 0.0001,再一步約為 0.00000001。白話說,正確位數每一步大約翻倍。三、四次好的迭代,就能把你從一個粗略的猜測一路帶到完整的機器精度。
平方從哪裡來?把 f 在根附近做泰勒展開。牛頓步精確地消去了誤差的常數項與線性項——這正是「使用切線斜率」的全部用意——剩下的領頭項就是由 f'' 主宰的二次項。推算下來得到 e_{n+1} 大約等於 (f''(r) / (2 f'(r))) 乘以 e_n^2。讀一讀這個常數:曲率 f''(r) 是敵人(彎得越多,越慢),而分母裡的斜率 f'(r) 是朋友(穿越得越陡,越快)。這就是收斂階等於 2——嚴格地比二分法或一般壓縮的線性階 1 還快。
一個小小的實例:根號 2
讓我們實際感受一下「翻倍」。要找 sqrt(2),就找 f(x) = x^2 - 2 的根,它的導數是 f'(x) = 2 x。代入 x_{n+1} = x_n - f(x_n)/f'(x_n) 並化簡,得到著名的巴比倫公式 x_{n+1} = (x_n + 2/x_n) / 2——把你的猜測,與「它得搭配誰相乘才等於 2」的那個數取平均。刻意從粗略的 x_0 = 1 開始,整整差了答案 0.41。
n x_n error |x_n - sqrt(2)| 0 1.0000000000000000 4.1e-1 1 1.5000000000000000 8.6e-2 2 1.4166666666666667 2.5e-3 3 1.4142156862745099 2.1e-6 4 1.4142135623746899 1.6e-12 5 1.4142135623730951 0 (to double precision) sqrt(2) = 1.41421356237309515 ...
最後那一行藏著兩個誠實的教訓。第一,誤差並不會真的走到零——它在約 10^(-16) 處停滯,因為每個數值答案都是近似的,而一個浮點數根本無法精確表示 sqrt(2)。牛頓法收斂到的是「可用的最佳雙精度數」,而非實數的真值。第二,正因為這份平滑,你絕不能用 x_{n+1} == x_n 的精確相等去測收斂:捨入誤差會讓相鄰迭代在最後一個位元上永遠抖動。你該用一個容忍度來停止,下一節會把它釘清楚。
誠實地停止,以及重根的陷阱
你怎麼知道該收手?你無法盯著真誤差 e_n,因為你不知道根 r。你改盯替身。最便宜的是殘差 |f(x_n)|:當它低於一個小容忍度時,x_n 至少在「f 在那裡幾乎為零」的意義上算是近似根。另一個常見的訊號是步長 |x_{n+1} - x_n|:一旦一步幾乎不再移動你,你大概已經抵達。一個穩健的停止準則會用相對容忍度,例如在 |x_{n+1} - x_n| <= tol 乘以 |x_{n+1}| 時停手,因為沒有尺度的絕對門檻毫無意義——10^(-8) 的容忍度對奈米太鬆,對光年則荒謬。
有一種結構性的情況,會讓牛頓法即使起點完美也丟掉它珍貴的速度:重根。若 f 以相切的方式碰到零——例如 f(x) = (x - r)^2,此時 f'(r) 也等於 0——那麼「消去線性項」的推導就破功了,牛頓法從二次一路退化成僅僅線性收斂,以每步約 1/2 的固定倍率龜速爬向 r。更糟的是,除以一個正趨向零的 f' 會放大捨入誤差,使最後幾位變得帶雜訊。一旦你懷疑重數為 m,解藥是修正步 x_{n+1} = x_n - m 乘以 f(x_n)/f'(x_n),它能恢復二次速率。更深的重點:牛頓法的卓越速度是單根的性質,而非普世定律。
為什麼這很重要,又通往何處
牛頓法是驚人大量計算底下的主力。每當軟體在硬體上算倒數或平方根、計算隱含波動率、擬合非線性模型,或對一個剛性方程走一個隱式時間步,通常都是某種牛頓式迭代在扛重活——正因為「每步位數翻倍」讓「搆到完整精度」變得便宜。同樣的切線想法在最佳化裡再度現身,化為求極小的牛頓法:你把它施加在 f' 上去找梯度為零之處,在行為良好的極小值附近獲得同樣的二次速度。
但牛頓法帶著一個真實的代價:它每一步都索求導數 f'(x)。有時你有乾淨的公式;但常常你沒有,或者它很昂貴,或者函數只是一個黑盒子。這個單一的要求,雙重地催生了下一篇。割線法用「穿過最近兩點的直線」取代精確切線——不需要導數——只付出一點點速度(收斂階約為 1.618,黃金比例,介於線性與二次之間)。而我們一直在暗示的那些失效模式——過衝、循環、由壞起點而發散——正是催生「把牛頓的速度包進二分法保證裡」那些有保護的混合法的原因。
最後,記住這個想法的「形狀」,因為本級的最後一篇會把它放大。求解單一方程變成了「線性化、走一步、重複」。求解一整個非線性方程系統,則變成一模一樣的舞步,只是斜率 f' 升格為一個偏導數矩陣——雅可比矩陣——而 f/f' 的除法升格為求解一個線性系統 J s = -f 來得到步長 s。先前各級的每一件線性代數工具(LU 分解、條件數、殘差檢查)都湧回來,為這一個非線性步效力。牛頓的切線不只是單一方程的把戲;它是貫穿整個數值計算、非線性求解的範本。