帳單在中途到期
到目前為止,這一級已經向你推銷了精確計算:符號答案不帶捨入誤差,任意精度算術讓整數能長到記憶體允許的極限,而一套電腦代數系統能交給你一個數值求解器只能近似的封閉形式。所以這裡有個整級內容一直在鋪陳的陷阱。精確不是免費的,而代價往往不在你尋找的地方支付。它在中途支付——在系統工作時必須保留的中間表達式裡。那種成長有個名字:表達式膨脹,它是符號計算的核心限制,是浮點數中捨入誤差的精確算術版孿生兄弟。
一個微小的例子讓它變得鮮明。把 (x + y + z)^4 乘開,你會得到 15 項——已經比你對三個字母的預期還多。推到 (x + y + z + w)^10,展開後的多項式有 286 項;把指數調高或多加一個變數,項數就像曲棍球桿那樣陡升。最終答案化簡後也許仍很精簡,但系統得先把那團中間的項雲實體化出來。問題只有三行;中間的工作卻是一面代數的牆。
膨脹從何而來
幾乎全部的膨脹都由三個來源驅動。第一是係數成長:當你對精確有理數做加減時,分母不會像浮點數裡那樣靠運氣消掉。在一個小整數矩陣上跑高斯消去法卻保持一切精確,消去中途冒出的元素,其分子與分母可以有上百位數字——即便最終的化簡矩陣又只剩小元素。計算的中段是一片沼澤,而兩端絲毫不曾暗示。
第二個來源是項數爆炸:把乘積展開,如同 (x + y + z + w)^10 的情形,會以組合方式倍增單項式的數目。第三、也最折磨人的,是演算法中的結構性成長:許多精確程序產生的中間結果,遠大於它們的輸入或輸出。由布赫貝格演算法算出的葛羅布納基底,其係數大小在最壞情況下可雙重指數成長——一座指數的塔——這正是為什麼多項式系統那篇警告你,一個看似無辜的系統可能實際上不可計算。透過里施演算法做符號積分也類似:判定一個初等反導數是否存在,是一場真正而深刻的計算,不是查表。
(x + y + z)^2 -> 6 terms (x + y + z)^4 -> 15 terms (x + y + z)^8 -> 45 terms (x+y+z+w)^10 -> 286 terms Gaussian elimination on an integer matrix, kept EXACT: input entries: 1-digit integers mid-elimination: 100s-of-digit rationals <- the swell final entries: small again # the cost lives in the middle, where you cannot see it from the ends
為什麼化簡不能直接把它刪掉
最直覺的反射是:邊走邊化簡就好,這樣東西永遠不會變大。這是個好直覺,系統也正是這麼做——但它撞上你兩篇前已經遇過的一面牆。要縮小一個表達式,你必須認出兩個長相不同的表達式何時相等,而這就是零等價問題:判定一個給定的表達式是否恆等於零。對夠廣的表達式類別——那些混了指數、對數與根式的——這個問題可被證明是不可判定的;沒有演算法能永遠回答它。所以系統無法保證它找到了最小的形式,因為它無法總是看出自己的某兩項會抵消。
局部的解藥是標準形式:約定一種特權的寫法來表示每個值,讓相等的東西變成字面上完全相同的字串,抵消便一目了然。在真正的標準形式存在之處,控制膨脹的工具就是本級稍早的多項式最大公因式——每個有理函數都靠把分子與分母同除它們的最大公因式而化到最簡,殺掉那些否則會堆積起來的假共同因子。但標準形式只對受限的類別存在(多項式、有理函數),它們算起來可能昂貴,而且標準形式本身可能就是那個大物件。化簡與表達式膨脹搏鬥;它並未廢除它。
與它共存:誠實的戰術手冊
你打不倒表達式膨脹,但一個老練的使用者懂得繞過它。這些技巧很巧妙、值得了解——它們是真實系統如何把那面牆往後推的辦法,即便無法把它移除。
- 模運算與代值技巧:對好幾個質數取模、或在好幾個數值點上計算,再重建出精確結果——即便符號答案巨大,中間的數字仍保持很小。
- 保持因式狀態:把表達式存成幾塊的乘積,而不是完全乘開,這樣只要你不是真的需要,展開的項數爆炸就永遠不會發生。
- 每一步都約簡:取最大公因式讓有理函數保持最簡,並重排葛羅布納基底計算的次序(變數排序會讓成本相差好幾個數量級)。
- 問一個更小的問題:一個定積分作為單一數字、一個數值根、或展開到幾項的級數,往往就是你真正需要的全部——而在完整封閉形式昂貴到毀滅性時,它卻很便宜。
收束本級:兩種正確的方式
退一步,把整個符號這一級看作一條論證。你學到精確與近似計算是為兩種不同工作打造的兩台不同機器:數值算術快速、大小固定,卻總是帶著捨入誤差,而精確算術不帶誤差,卻讓資料無界地成長。你遇見了標準形式與判定相等的那面硬牆;解決多項式問題的歐幾里得最大公因式與葛羅布納基底;以及符號微分(機械化的)對上積分的里施機制(深刻的)。表達式膨脹是把這一切串起來的那條線——每一個精確方法都被釘上的價格標籤。
留意這門學問的兩半如何乾淨地互相映照。數值計算在空間上有界,卻在準確度上失血:每個答案都是近似,條件數與穩定性決定多少位數能存活,而你永遠到不了實數算術的理想值。符號計算在準確度上完美,卻在空間上無界:每個答案都精確,但工作可以膨脹到超過你擁有的任何機器。捨入誤差與表達式膨脹是同一個教訓穿著不同的衣服——沒有任何方法能同時又快、又精確、又小。你永遠在交換。
所以成熟的姿態,不是替某一台機器加冕。而是兩台都懂,讀一個問題並問它實際需要哪一種正確,並且常常把兩者編在一起——用一套電腦代數系統找出結構,用浮點數大規模地求值。精確無法擴展;近似永遠不精確;而計算數學的手藝,就在於誠實且有意地選擇:對眼前這個問題,你寧願與哪一種限制共存。