# 唐納德·克努特：程式設計、演算法、難題與生命遊戲

> 電腦科學泰斗談《計算機程式設計藝術》的寫作、演算法之美、攻克難題的樂趣與生命遊戲。

- 原標題：#219 – Donald Knuth: Programming, Algorithms, Hard Problems & the Game of Life
- 期數：第 219 期
- 釋出日期：2021-09-09
- 嘉賓 / 主題：唐納德·克努特：程式設計之道
- 網頁版：https://lex.qiaomu.ai/tw/ep/donald-knuth-2/
- 官方頁面：https://lexfridman.com/donald-knuth-2/
- 精讀字數：約 13040 字（閱讀約 29 分鐘）

> 本文為 lex.qiaomu.ai 基於原始訪談的 AI 改寫中文精讀，非官方翻譯；引用請註明出處並連結網頁版。

1957 年夏天，一個還沒念完大一的年輕人夜裡獨自坐在 IBM 650 的控制檯前，用十進位制數字一位一位撥進指令。他要讓這臺機器把開關上設好的數字分解成質因數。

那個年代幾乎沒人聽說過彙編器。他看的是隨機附帶的手冊，上面寫著 69 表示裝載，後面接上要裝入的地址。一條指令是十位十進位制數：兩位說明做什麼，四位說明對哪個地址做，剩下四位說明下一條指令去哪兒取。整臺機器的記憶體是兩千個字。

這個年輕人叫唐納德·克努特（Donald Knuth）。

他後來講過一句很實在的話：如果那本手冊寫得好，他大概不會走上電腦科學這條路。正因為寫得實在太差，他一邊讀一邊想，我一個新生都能寫得比這強，看來我在這上頭有點天賦。於是他跑到學校的計算中心打工，開始寫手冊。

前幾天，計算機歷史博物館的朋友道格·斯派瑟給他發了一個剛上傳到 YouTube 的連結：IBM 1956 年的進度報告。那年 IBM 把 650 捐給了斯坦福、MIT 和他所在的 Case Tech，影片裡能看到裝配線上第五百臺下線。片子還拍到一間教室，老師在黑板上寫著 69 8000，正在教學生怎麼給這臺十進位制機器寫程式。

克努特就在那樣的教室裡起步。

## 第一個程式除錯了一整夜，最後程式碼行數比預想的多出一大截

他的第一個程式是因數分解。輸入是控制檯上的撥盤，輸出打在穿孔卡片上。最初大概二十行，寫完開始除錯，行數就開始往上漲。

除錯的方式很原始。晚上沒人的時候，他坐在機器前，撥一個數，然後按單步執行，看機器做了什麼。有四組開關可以設一個地址，機器執行到那兒就停下來。他就這樣盯著它把這個數除以二，沒有餘數就說二是因子，有餘數就換三，一直試到開方為止。

第一個晚上他大概就跑通了 30 等於 2 乘 3 乘 5。之後麻煩陸續出現：有些數的因子多到一張卡片裝不下，而一張卡只有 80 列，每個因子要佔 10 列，他一開始根本沒考慮要輸出到第二張卡；如果輸入的是一個很大的質數，程式會在那兒空轉十分鐘，這臺機器慢得讓人分不清它是在計算還是卡在死迴圈裡。

第二個程式簡單得多，二進位制轉十進位制，幾乎沒出什麼岔子。第三個才是井字棋。

## 三個大腦，其中一個自己學會了不輸

井字棋那件事值得細說，因為裡面藏著一個十八九歲的年輕人對“學習”這件事最早的直覺。

棋盤是三乘三，每個格子有三種狀態：空、叉、圈。總共三的九次方，一萬九千六百八十三種局面。IBM 650 只有兩萬個十進位制數位的儲存，還得塞下程式本身、人機互動的邏輯、輸出邏輯。他做了一件事：利用對稱性。棋盤轉四次、翻一次，八種等價的擺法算一種，儲存需求一下降到八分之一。

每個見過的局面存一位數字。零表示壞棋，九表示好棋，初始值大概設成五六。贏了就把這個局面對自己調高，對對手調低。

他把程式分成三個大腦。第一個大腦完全隨機，輪到它就隨便找個空格打一子。第二個大腦是內建的固定策略，一套已知最優的走法。第三個大腦是真的在學。

然後他讓第一個大腦和第一個大腦對打。大約六百局之後，兩個什麼都不知道的隨機玩家，收斂到了一定和棋。

這個結果值得停一下。隨機對隨機，本來是亂打，最後變成了誰都不犯錯的穩健局面。原因在於他設計獎勵函式的方式：**他懲罰的是錯誤，妙手反而沒有額外獎勵。**這個學習系統學會的是不輸，不是想贏。他自己也點破了這一點，說如果換一個獎勵函式去獎勵漂亮的走法，學出來的東西會完全不一樣。

> “它在學習怎麼不犯錯誤，它沒想贏，它只想別輸。”（唐納德·克努特）

他還提到兩件往事。查爾斯·巴貝奇一百多年前就在琢磨給那臺永遠沒造完的差分機編一個井字棋程式。而他自己上大學的動機之一，是小時候在芝加哥科學與工業博物館看過貝爾實驗室做的繼電器井字棋裝置，那時他就想著，我是不是也能寫一個。

## 凌晨的機器與停機時間寫出來的 TeX 手冊

那幾年他用機器只能靠夜裡。全世界都在睡覺，算力才輪得到他。高中時做校報，週一晚上整夜不睡，週二早上報紙出來。大一大二之間他基本不需要睡眠。

羅德尼·布魯克斯（Rodney Brooks）講過一件舊事。他在 MIT 的時候對克努特有點發怵，因為機器壞了，這位個子很高的教授就站在旁邊等，壓力全在修機器的人身上。克努特自己的版本更平淡：斯坦福 AI 實驗室的機器宕得厲害，因為那兒有一群天才程式設計師每天都在改作業系統，系統一天比一天好，也一天比一天容易崩。

TeX 的手冊，很大一部分就是在那臺機器宕機的間隙裡寫完的。

## 一張餐巾紙，一週寫完一本書

1967 年，克努特在牛津第一次見到約翰·康威（John Conway）。那場演講講的是紐結，康威拿一堆塑膠小棍在臺上現場拼出各種結，拼完再拆掉。他講的東西后來引出了成千上萬篇論文，而那些內容他在高中就想過，一直沒發表。

1972 年春天，兩人碰巧同一天到卡爾加里，一起吃了頓午飯。康威在餐巾紙上寫下了他關於“數”的那套公理，寫得滿滿一張。克努特看完覺得極其漂亮。

那年年末，他在挪威過學術休假。十二月的一個深夜，他忽然想到：康威這套數的理論，正好可以用來教學生怎麼做研究，怎麼體會發現的樂趣。他之前還讀過阿爾弗雷德·雷尼寫的一本對話體小書，兩個角色像蘇格拉底那樣互相追問數學。凌晨他把妻子吉爾叫醒，說我想寫一本書。

一月份，他在奧斯陸市中心租了一間旅館房間，除了寫這本書什麼都不幹。一個星期，白天黑夜連著寫。**字流出來的速度幾乎比他思考還快。**寫到第六天完成，第七天休息，然後他準備給秘書寫信交代怎麼打字，發現自己寫不出一個完整的句子了。

> “靈感完全離開了我。就好像是在通靈。”（唐納德·克努特）

稿子寄給康威，康威回信說，唐，你有一條公理寫錯了。他用的是“不大於”，而應該是“小於等於”。在日常語言裡這兩個說法差不多，在邏輯公理系統裡，選錯一個會讓後面每一步證明都變難。那年夏天他又抽出一週，跑到挪威山裡重寫了一遍。

書最後叫《超現實數》（Surreal Numbers）。一本講數學的書，寫成了兩個人的對話，寫的過程本身就是書裡講的那個過程：從兩條公理出發，一步步發現，作者犯的每個錯，書裡的角色也犯一遍。

這兩個人後來的交往也很有意思。克努特在蒙特利爾做七場關於穩定匹配的系列講座，康威在第六場和第七場之間到了，兩人在派對上碰面，克努特講了自己在做什麼，康威當場想了一會兒，推出了一套漂亮的理論：所有穩定匹配構成的集合是一個分配格，還給出了求兩個穩定配對的下確界和上確界的方法。第二天的講座就用上了。

穩定婚姻這個詞，克努特用了六十年。他和吉爾結婚也正好六十年。他們認識的方式是他先跟吉爾的室友約會，然後跑去問吉爾該怎麼追。他發現聽她出主意比追她室友有意思得多。一個藝術家，一個極客，一起做設計專案，每年寫聖誕卡都要互相妥協各自對美的理解。

他說了一句話，婚禮上大概沒人敢講：在遇到她之前，他其實並不喜歡接吻這件事。

## 費曼問了一個沒人問過的問題

在加州理工，他和費曼會互相去聽對方的講座。費曼要是坐在第一排，他會走神，會漏掉幾句話。

他印象最深的是費曼在巴西的那段經歷。費曼說那兒的物理教育全錯了，學生只是在學怎麼透過考試，沒在學物理。別人不信，他說你把書翻到任何一頁，我告訴你這一頁錯在哪兒。那本教材的作者就坐在臺下，還是位很好的老師。

克努特從中提煉出的東西，比故事本身更重要：**教育機構很容易滑向發證書，把給知識這件事放到了一邊。**他自己講過一個鮑勃·弗洛伊德喜歡的漫畫：兩個人站在一臺大機器前面，一個說這機器一秒鐘能幹一百萬人一百年的活，另一個問，那你怎麼知道它算得對。

他和費曼之間還有一段純粹智力上的交鋒，關於他名字掛在上面的那個記號：克努特箭號。

加法重複若干次變成乘法，乘法重複若干次變成冪，冪重複若干次就是雙箭號。二的二次的二次，二的二次方是四，二的四次方是十六。三箭號、四箭號可以一直疊上去，數字會迅速膨脹到人腦無法把握的程度。他用這個來舉例說明什麼叫“大到無法理解”。

費曼聽完說，那我們別隻用整數，考慮考慮複數。x 雙箭號 2.5 可以插值，那 x 雙箭號 i 呢？他斷言不存在能做這件事的解析函式。克努特當時沒弄明白他憑什麼這麼斷定。然後費曼接著問：那箭號的個數能不能是複數？

這就是費曼式的提問方式。克努特講這段的時候語氣很平靜，但你能聽出來他記住這個提問已經幾十年了。

他還解釋過自己為什麼從物理轉到數學。物理考試他能拿 A+，但他完全不知道老師是怎麼想出那些題的。數學不一樣，他知道題目為什麼這麼出，還能自己編題。他擅長代數，不擅長几何。物理學家用波思考，他也能用波思考，但那感覺像一條狗用後腿走路。能走，但不像它的本能。

他相信電腦科學很大程度上是被那些大腦恰好能和某類概念共振的人推動的。量子計算就屬於需要另一種大腦的東西，它正好卡在物理和電腦科學的交叉口上。

## KMP 演算法：三個不同的人摸到了同一頭大象

字串匹配這個問題，今天每個用搜尋引擎的人都受益於它。你有一大段文字，想知道“Knuth”這個詞出現在哪兒，或者某個比 Knuth 更沒意思的詞出現在哪兒。

樸素做法是：從頭掃，先找 K，找到 M，再找 O，一路下去，但遇到“Morris”這個詞，讀到第五個字母發現是 E 而不是 I，只能退回下一個位置重來。加州大學伯克利分校的吉姆·莫里斯（Jim Morris）注意到一個巧妙之處：剛才那幾個字母已經讀過了，而且它們不可能是 M，沒必要重讀。

如果模式詞像“abracadabra”這樣，開頭、中間、結尾都有重複的花紋，事情就變得很微妙。

莫里斯把這個想法寫進了伯克利 Unix 的系統軟體裡，但他沒寫解釋。幾個月後有人翻到這段程式碼，看看覺得不對勁，刪掉了。**演算法做出來了，沒人看得懂，就等於沒做。**

沃恩·普拉特（Vaughn Pratt）一兩年後獨立發現了同樣的東西，當時他研究的其實是迴文問題，跟文字搜尋八竿子打不著。克努特自己則是從另一個方向過來的，而且路徑相當繞。

那會兒史蒂夫·庫克在伯克利當教授，克努特說伯克利計算機系最大的失誤就是沒給他終身教職，後來庫克去了多倫多。庫克證明過一個關於棧自動機的定理：這種機器只能看棧頂，只能後進先出地存取，沒有別的記憶，比圖靈機弱得多；但如果它能識別某個語言，那麼一個普通計算機一定能在 n log n 的時間內識別同一個語言。

這個定理聽起來純粹是理論上的漂亮話。克努特拿它試了一個自己知道棧自動機能做、但想不出快辦法的問題。他自認是個不錯的程式設計師，可就是想不出來。於是他把庫克的構造一步步寫在黑板上，填滿一整塊，然後盯著那堆東西找規律。最後他看明白了。

> “我之所以能寫出那個高效程式，完全是因為手裡有那個純粹抽象的定理。”（唐納德·克努特）

他寫過一篇小文章，標題叫《自動機理論可以是有用的》。在那之前他讀過大量自動機理論的論文，但它們從沒改善過他日常程式設計的水平，那些東西只是發表在期刊上、看起來有趣的內容。這一次不一樣：他想不出怎麼寫程式，手上有一個自動機理論的定理，然後他就會寫了。他說這是他人生中的一個轉折點。

他把這份筆記給普拉特看，普拉特說這跟我做的東西很像。三個人各自獨立發現了同一件事，每個人摸到的是大象的不同部位，拼起來就完整了。論文的署名按字母順序排，所以叫 KMP，其實應該叫 MPK。

## 他這輩子解過的最難的題：把大爆炸放慢

問到他遇到過最難的問題，他沒怎麼猶豫，答案很明確：巨組元的誕生（the birth of the giant component）。

先講背景。有 N 個點，彼此完全平等，沒有距離，沒有幾何。取出 π 的十進位制數字，兩位一組：31、41、59、26，拿第一組和第二組連一條邊，拿第三組和第四組連一條邊。或者乾脆擲骰子，每次隨機挑兩個端點連起來。**π 在這裡沒有任何特殊性，只是沒人知道它的規律，拿來當隨機源用。**

邊一條一條加上去。埃爾德什和雷尼研究過這個過程，叫隨機圖的演化。

神奇的地方在這兒：當邊數是 0.49N 的時候，比如一百萬個點、四十九萬條邊，圖幾乎全是一棵一棵孤立的樹，連一個環都沒有。而邊數變成 0.51N，五十一萬條邊，就會出現一個比其它所有連通塊大得多的塊。這就是巨組元。

幾乎就是相變。但它是個雙重相變，兩件事同時發生，這才是真正引人注目的地方。

伯克利的迪克·卡普有一批學生在模擬這個過程，每過一陣子給圖拍一張快照。然後傳出一個小道訊息：幾乎每一次觀察，都只有一個連通塊裡帶環。他們做了上百萬次實驗，只有三四次看到有一個以上的塊帶環。

斯坦福這邊聽到這個訊息，克努特他們的反應是：如果這是真的，那一定還有更多東西是真的，有一整套理論等著被發現。仔細一看，訊息不完全對，但幾乎對。**確實存在兩個或三個帶環的塊同時存在的時刻，但那個時間視窗極短，快門速度不夠就拍不到。**

於是問題變成：怎麼把這場大爆炸放慢，看清楚中間發生了什麼。

他定義了一個叫“複雜度”的量：邊數減去頂點數。一棵樹有十個點九個邊，複雜度是負一。一個單環連通塊，環上掛著一堆樹，邊數等於點數，複雜度是零。多一個環就多一條邊，複雜度是一，那叫雙環。複雜度加一就是環的個數。

演化過程是這樣的：先出現一個環；下一步，按那個小道訊息，應該變成雙環；但實際上有相當的機率，大約二十四分之五，分裂成兩個各自帶環的塊。再下一步，可能變成三個，也可能是一個雙環加一個單環，也可能是三個單環。

他把前五次躍遷的機率全算了出來。算到凌晨三點，數字出來了，分母是 23023。他盯著這個數看：1001 等於 7 乘 11 乘 13，這是他人生第一個程式教會他的事。23023 等於 7 乘 11 乘 13 乘 23。

**一個隨便的分數不會這樣分解。分母裡出現這些小質數，說明背後有個理由。**他當即換個角度，取對數，公式果然簡化了。

第二天，比爾·蓋茨來斯坦福，學校想說服他給新計算機系大樓捐錢。他們安排克努特去見蓋茨。他就把黑板上那張從一變到二、二十四分之五的演化圖講了一遍。當天結束時蓋茨跟發展辦公室的人說，那位克努特教授講巨組元的那段，我印象太深了。

克努特喜歡講這個故事，因為它說明理論電腦科學真的有用。

後來他和兩位合著者把整個問題做完了：那條小道訊息所說的“任何時刻都只有一個帶環的塊”，真實機率不是百分之百，大約是百分之八十七，而且能用 π 表示出來，形式像 12/π² 或者 8/π 那樣的東西。那是他這輩子證明過的最難的定理，花了很大力氣，也給隨機圖理論裡一大堆其它問題照了亮。

順帶說一句，這套東西和物理是通的：玻色愛因斯坦統計研究的正是分子如何在完全沒有幾何的情況下結合到一起。

## 為什麼 TeX 是開源的：收入是個閾值函式

TeX 釋出的時候，“開源”這個詞還不存在。他不要所有權。

因為他親眼見過所有權怎麼拖住一件事。五十年代末，IBM 的人做出了 Fortran，他們本可以規定只有 IBM 的機器能用這個語言，但他們沒有，他們說，誰能把 Fortran 翻譯到自己機器上，誰就可以做編譯器。反觀排版行業，每家廠商都有自己的頁面描述語言，使用者被綁死在某一家裝置上，一年後新機器出來，可印刷裝置的成本要攤二三十年。

他也不需要這筆錢。他有穩定的教職，書賣得夠多，孩子的教育費用不愁。

> “收入是個閾值函式。不夠就是捱餓，過了那條線，你要麼開始想慈善，要麼開始想著怎麼把它帶走。”（唐納德·克努特）

他有一套自己的判斷標準：**非平凡的軟體應該收費，平凡的軟體不該收費。**他舉 Adobe Photoshop 的例子，說裡面有些真正諾貝爾獎級別的智慧財產權，那個撤銷功能可以在上千步複雜操作之後回到任意一箇中間狀態，背後一定有非常漂亮的演算法。專利的意義在於公開，讓人不能把它當商業秘密藏起來。

而他自己那臺筆記本跑 Ubuntu，不聯網，只用 U 盤在自己的 Mac 和它之間搬東西。原話是：**我只把最重要的家當託付給 Linux。**

## 你喜歡的字母、數字或符號是什麼

他翻到書的索引最後一頁，指著一個符號給採訪者看。那個符號來自蘇斯博士（Dr. Seuss）的《On Beyond Zebra》，書裡給這個符號起了名字。他說他小時候能把《Bartholomew Cubbins》背下來。蘇斯博士五十年代初還拍過一部電影，裡面有幾十架鋼琴同時演奏，整個佈景就是他繪本里那種奇想風格。

說到自己偏愛的符號，是 π。

理由很實用：需要一個隨機例子的時候就用 π，因為它沒有已知的規律。他拿出一個叫 Masyu 的謎題來舉例。盤面上有黑石和白石，像圍棋，要求畫一條閉合路徑，穿過白子時直行，經過黑子時必須直角轉彎。這個謎題好玩的地方在於不需要數字，純視覺，但比數獨更上癮。

他想把它寫進《計算機程式設計藝術》當例題，還寫了習題教人怎麼設計漂亮的 Masyu 題。於是他給自己出了個難題：拿 π 這個希臘字母的畫素圖，在每個該有石子的位置放一顆石子，然後給其中一些染成黑色、一些留白，要求整個謎題有唯一解。

結果真的存在唯一一種染色方式。

> “π 是我用來舉例子時能證明自己沒有抄現成東西的來源。”（唐納德·克努特）

## 把美國地圖做成優雅標號，有人順手把 π 嵌了進去

他最近在寫優雅圖（graceful graph）。規則是：給每個頂點一個編號，每條邊連線的兩個頂點編號之差，恰好構成從 1 到邊數的一個排列，每條邊佔一個差值，一個不重複。

他拿了一張完全不對稱的真實地圖來試：美國四十九個州，加上哥倫比亞特區，阿拉斯加和夏威夷不算，因為得能開車過去。加州和俄勒岡、內華達、亞利桑那相鄰，每條相鄰關係是一條邊。問題是，能不能給每個州一個編號，讓所有邊對應的差值不重不漏？

他原本想搞個競賽，因為他自己只做到把所有邊的差值控制在一到一百一十七之間，中間還有空缺，實際上應該是一到一百零五左右。他的朋友湯姆·羅基茨一個下午就做出了完美解，競賽還沒開始就結束了。

更妙的是兩天後羅基茨回來說，他不僅找到了優雅標號，還讓華盛頓州的編號是 31、愛達荷州是 41，沿著美國北邊那條邊界，編號正好是 π 的數字。

克努特講這件事的時候是很高興的。他喜歡用 π，而 π 總會在最難的問題中間某個地方冒出來。

## 讀程式碼能認人：風格是技術能力，標點符號算不得什麼

他說自己讀程式的時候，能看出作者換人了。

他舉的例子是一個卡內基梅隆團隊寫的編譯器。讀到某一段，那個人明顯不知道怎麼高效地在暫存器之間搬東西，本來一條指令能做完的事要三條。這就是很明顯的風格切換。然後又有一些靈光一現的地方，一條指令幹了兩件事，因為那個人足夠了解機器，知道怎麼一步達成兩個目標。

> “我能靠技術水準認出作者，但認不出節奏意義上的風格。”（唐納德·克努特）

那他自己的程式碼有什麼可辨認的特徵？他說現在都是文學化程式設計，英文和 C 混在一起。如果只看 C 那部分，別人大概會注意到他用大量全域性變數，別人不這麼用；他更傾向於內聯展開而不是函式呼叫；他用的是 C 的一個子集。

## 文學化程式設計是他自己認為最重要的產出

他說，TeX 專案帶來的最重要的東西是：他意識到**程式是給人讀的，不只是給計算機讀的，而排版能極大地增強這件事。**

他推薦了一本書，《Physically Based Rendering》，作者是 Matt Pharr 等人，拿過奧斯卡獎。電影裡所有的圖形特效都是演算法做出來的，而整本書就是一個文學化程式，不只告訴你陰影怎麼算、動畫和紋理需要的影象怎麼匯入，程式碼還能直接跑。

他把這看成教學程式設計的一種延伸：把程式當成一個故事來講。

> “它作為程式能跑，同時人也能讀，尤其是一週之後或者一年之後的我自己。”（唐納德·克努特）

這是他自己設的驗收標準。一週後、一個月後、一年後，你自己還能不能輕鬆看懂。

## 什麼是優美的程式

他之前被問過這個問題，迴避了。這次他說了為什麼迴避：答案有幾十個，取決於你此刻在找什麼。

一個層面上，能跑就美。另一個層面上，容易看懂就美。文學化程式設計的形態也美。還有，它讓你笑出來，也是美。

他提到幽默這件事。有人問過他程式碼註釋裡該不該有幽默，他的答案是該。他給出一條很講究的標準：**理想的情況是，讀者知道這兒大概有個笑話，只是還沒看懂，於是有了動力去想。**

《計算機程式設計藝術》第一卷的初稿，主要審稿人是鮑勃·弗洛伊德。出版社把稿子拿給他看，他還專門問，這個笑話留不留。出版社甚至組織了焦點小組，問大家對一本講計算機程式設計的書裡有幽默怎麼看。他堅持了自己的原則，而且書裡還留著一些至今沒人解出來的笑話。

第二卷裡有一個密文。要解開它，得先破一個比現在人類已知方法能破的還要大的 RSA 金鑰。他說，如果計算機一直變快，也許一百年後會有人解出來，然後笑一下。

## 過早最佳化是萬惡之源，這話是在什麼語境下說的

他先澄清了“最佳化”這個詞在當時的意思。那會兒他是編譯器作者，最佳化指的是讓翻譯出來的程式碼在機器上跑得更快，就是給編譯器設最佳化等級那件事。他當時翻未刪節詞典，看到 optimizer 這個詞的解釋是“以樂觀的態度看待”。

他那句話針對的是另一種現象：**寫程式的人會以為，自己寫得最費勁的那幾頁，計算機執行起來也最費勁。**十頁程式碼，其中一頁折騰了一個星期，於是潛意識裡覺得機器讀到那一頁也會慢下來，會“看不懂，得小心點”。這當然很荒唐。

他做過一次測試。分析一個 Fortran 編譯器，發現它超過百分之八十的時間花在讀註釋卡上。而寫編譯器的人整天操心的是怎麼把帶多層括號的複雜表示式翻譯好，那部分連百分之一都不到。如果早知道八成時間在讀註釋卡，十分鐘就能讓編譯器快一倍以上。

這種認識只能來自程式寫完之後的實測，來自 profiling。

但他強調這句話還有另一層意思：有時候一種最佳化確實提升了執行速度，代價是程式下個星期就改不動了，因為你把資料結構換了，適應性沒了。所以電腦科學裡有一條重要原則叫延遲繫結，能晚決定的就別早決定。他說現在已經有人量化地研究過，延遲決策在製造業、在各種領域都有它的最優性。

而這句話之所以被這麼多人記住，是因為程式設計師心裡確實有一種對最佳化的偏愛。一份最佳化得極好的程式碼有它的優雅，那是另一種美。

## Copilot、自動化，以及“讓人開心”和“正確”之間的選擇

採訪者給他講了 GitHub Copilot：寫幾行註釋，說明這段程式碼要幹什麼，它就把函式補全。用的是 OpenAI 的 Codex。採訪者說，這裡面有文學化程式設計的影子。

克努特聽完先追問了一句：**那你怎麼知道它做得好不好？**

然後他講了一個六十年代加州理工的同事。那個人課講得極好，聽完一小時你覺得全是激動人心的東西，再過一小時你回想，他到底說了什麼？那個人真的相信，計算機算得對不對不重要，重要的是它讓你開心。你老闆付了錢，你有了工作，能養活老婆孩子，這就行了。

> “他相信快樂比真相更重要。他不相信有真相，不過他是個哲學家。”（唐納德·克努特）

他說這種思路正在擴散。越來越多的事情被“看起來能跑就行”接管。當有利益衝突的時候，兩邊都不明白決定是怎麼做出來的。現在大家還知道這是壞事，可五年十年之後，一層一層疊上去，就徹底脫鉤了。

反面他也認：自動化程度越高，人越能去做人最擅長的事。也許程式設計師該專注於程式設計裡那一小塊需要天才、需要人類心智的魔法，剩下的雜亂部分交給機器生成。

但他劃了線。他說自己永遠不會推薦學生去那種地方工作。**他要的是理解。正確和快樂都排在它後面。**如果這些工具帶來的是更好的醫療診斷，是幫某個科學實驗找到方向，是攻克疾病，那真是妙極了。可如果它影響到人的生命，那就得非常小心。現在看著像玩鬧，寫個小 JavaScript 幫網站做點事。一年、兩年、五年過去，你忘了底下的東西，你在上面繼續蓋，最後就是自主武器系統。

他也不迴避最終結局，這一點他看得很開：宇宙終有熱寂，他只是想把那件事往後推一推。而如果真到那一天，最好還有某種意識存在，能欣賞它。最好是人類的意識。

那費米悖論呢？為什麼收不到外星訊號？也許是他們也發明了這個東西。

## 他為什麼還抱有樂觀

他沒有直接回答樂觀還是悲觀，而是讓人看這個房間：鉛筆、書、桌子、麥克風、衣服、食物，每一樣都是某個人一件一件發明的。幾百萬人、幾十億件東西，我們繼承下來的這一整套文明。

這麼多東西，每一樣都可能出問題，每一樣都可能帶來負面效應，而它居然大體上運轉著。這非常不可思議，而這正是他樂觀的來源，人工智慧也不例外。

> “我們開著車過橋，用著各種根本不知道怎麼運作的技術。幾百萬聰明人各負責其中一小塊，它大體上不出錯，出錯的時候我們能發現，然後改進，雖然常常改得不太理想。”（唐納德·克努特）

但緊接著他補了一句，語氣很輕：**他能想到的改進辦法，都要求人是理性的。而他對人是否理性這件事，信心正在流失。**

採訪者接話說，人也許不理性，但人很聰明，而且以自己的方式很美。多數人有對彼此好的意願，只要有機會，愛最終會贏。

## 彭羅斯、意識，以及“超出知識範圍”

羅傑·彭羅斯主張，人發現數學觀念的方式不止是計算，圖靈機做不到人腦能做的全部事情，他寫過一本關於意識的書。克努特的女兒的孩子和彭羅斯的孩子在牛津一起玩過。

克努特說，他可以回答是或不是，但他沒有理由。他反覆強調自己在這上頭沒有專門知識。**這是個無法回答的問題，這話的意思只是他現在看不清，還談不上永遠看不清。**

他打了個比方，有多少天使能在針尖上跳舞。他說，這樣的事我們可以推測，但他不希望別人說，克努特說過這個，所以他很聰明，所以那一定是對的。他真正想說的是：現在還沒到能問清楚的時候。

採訪者說他個人相信，人類心智的運作終有一天在科學可及的範圍內。克努特說，這完全可能，我並不否認，只是你現在問我，我沒法給出判斷。他還接了句玩笑：也說不定宇宙是某個 AI 造出來的，智慧設計什麼的，全是一個 AI 乾的。

他也提到約翰·麥卡錫對這類主張完全不以為然。還提到二十年前在美國藝術與科學院的一次研討會，開場就說，關於意識寫過的一切都是胡扯。他不太同意這個說法，但也沒打算站在哪一邊。

真正讓他覺得有意思的是那些實驗：神經學家指出，人在意識到自己做出決定之前，訊號已經送到手臂上了。還有萊斯·瓦利安特給出的一個大腦架構，以及克里斯托斯·帕帕季米特里烏一年前在《美國科學院院刊》上和另外兩人發表的模型，這個模型能產生與意識實驗相當吻合的結果，而且有一套機器語言，可以在上面寫程式碼、檢驗假設。

他自己最認可的解釋是這樣的：**大腦內部是一場持續的適者生存競爭。**他現在說話，所有可能想說的東西都在裡面，像一場投票，某一句話贏了，它影響下一句。聽起來像有一個清晰的敘事在發生，像他本人在掌控，可底下可能是一堆想法在激烈競爭，最後機器編出一個連貫的故事給你，讓你相信。

他把這比作文學化程式設計。你不知道底下在跑什麼程式，但你拿到了一個好故事。

## 生命遊戲：他不覺得自己在玩弄生命，但他會猶豫要不要關機

他說生命遊戲是絕妙的東西，展示了在創造者什麼都不懂的情況下，事物怎麼自己演化起來。

但對他而言，生命遊戲最重要的意義在別處：**它把自由意志這件事說清楚了。**它顯然是徹底決定論的。可他說，任何有過孩子的人，都很難不相信自由意志。

康威說過，當他玩到某局特別有意思的時候，會猶豫把計算機關掉是不是不道德。

從簡單的初始條件、簡單的規則出發，你完全知道系統在怎麼運作，它是決定論的。可只要你允許自己忘掉一部分細節，退後一步去看那些湧現出來的更大的結構，它們看起來就像活的。

採訪者接了一句：如果宇宙是有限的，那我們其實都活在生命遊戲裡，只是更快一點。

至於能不能用分析演算法的方法分析生命遊戲，克努特說可以，他在第四卷第六分冊裡有十幾個習題就是幹這個的。他還提到比爾·戈斯珀的演算法讓 Golly 跑得快了成千上萬倍。

## 把最討厭的事放在最前面

他的時間安排原則是：每天先做待辦清單上他最討厭的那件事。週末回頭看，會很愉快，因為討厭的事都幹完了。

他媽媽教過他另一條，跟搞機器人的人說的“規劃”不太一樣：看見有什麼需要做，就去做。別先排個一二三，看見了就撿起來。

這兩條怎麼並存？他的說法是，任何時刻手上都有一組任務，那麼一個好的啟發式是，先做那個你最不想做、而且再拖也不會做得更好的。有些事確實先做別的會更好，有些則相反，拖久了會把當初的思路忘掉，反而更難。

他剛寫完書裡一個很難的部分，現在在做比較有意思的部分。但寫書的時候，他希望讀者覺得他全程都很快樂，語氣是向上的，可以有幽默，可以說這個很酷。**他得把過程的痛苦藏起來。**通往那種興奮的路是痛苦的。

疫情期間他的效率掉了一半。原因是溝通全靠寫字，而寫字慢。他不願意發出一句寫得不好的話，所以要反覆讀、反覆改。還有圖書館關門之類的事。

## 給年輕人的建議：人生是二分查詢

他的建議跟以前一樣：不要因為某個東西流行就去做，要做你個人覺得被召喚去做的事，而不是別人期待你做的事。

怎麼知道自己被召喚了？試試看，成了或者沒成，你都會更瞭解自己。**人生就是一次二分查詢。**試一件事，發現自己在這上面有底子，或者發現只要再努把力就能做到。試另一件事，發現自己完全沒有直覺，看起來跟自己不搭。

他也承認自己有個反向的毛病：看見所有人都在往一個方向走，他會想，競爭有點激烈。

多數時候他只是玩自己覺得有意思的東西，後來才明白，他學到的最重要的一件事是**怎麼對幾乎任何事都產生興趣，怎麼不無聊。**

> “聽見小孩說這個好無聊，我會很難過。一個人如果不得不承認自己沒能力從一件事裡找到有意思的地方，他應該為此不安。”（唐納德·克努特）

他說這是一種技能，一種還沒學會怎麼享受生活的表現，非得有人來娛樂自己才行。

他提到在新冠疫情最嚴重的時候，很多天他見不到任何一個人，但他照樣能找到別的辦法，那段時間他過得相當愉快。那天他提前幾分鐘到了福斯特城，在附近走了走，在幾個街區外的家得寶苗圃看見一些很美的花。

> “生活充滿這樣奇妙的東西。有時候我就坐在那兒盯著樹看。”（唐納德·克努特）

## 生命的意義

他先拿 42 擋了一下，然後說了實話。

他信上帝存在，雖然他說自己完全不知道這句話是什麼意思。他相信有某種超出人類能力的東西存在，也許是某種 AI，不管是什麼。**他相信自己可以去摸索怎麼和那個存在想要他做的事共振。**

他說自己不敢說接近過，但他在努力。他做的選擇不帶策略性，他只是試著想象自己在遵循某個人（那個存在）的意願，哪怕他聰明不到能弄明白那是什麼。

那個存在大概聰明到能給他線索，也能讓從一個線索走到下一個線索的整段路程變得有趣。

他最近讀肯·福萊特的《來自聖彼得堡的人》，講一戰前的那段。書裡丘吉爾看到德國把黃金儲備全砸進了軍備，英國一旦被打就完了，所以想讓俄國從另一側夾擊，因為德國沒有足夠的兵力兩線作戰。而俄國有個無政府主義者認為，戰爭是領袖發動的，死的卻是普通人，所以他要去刺殺來訪的俄國親王，讓沙皇不籤這個同盟，這樣成千上萬本來不會死的俄國人就能活下來。

他讀完的感受是：如果他被放在一個要為他人生命負責的位置上，大多數情況下，他對自己的任何一個決定都不會有信心。這些問題對人類來說太難了，對他更是。

採訪者補了一句：對自己沒把握，同時又必須做出決定並承擔它，這兩件事合在一起其實是件好事。

克努特沒有反駁。他說他對人有信心，偉大的領導者會出現，幫助建設一個更好的世界，這就是民主的希望。採訪者說，希望我們能用手上的演算法增強他們的能力。

節目最後，他留給聽眾的是一句他自己說過很多次的話：

> “科學是我們理解得足夠透徹、可以講給計算機聽的東西。藝術是我們做的其它一切。”（唐納德·克努特）

這句話可以當作整場對話的註腳。他這一輩子在做的，就是把儘可能多的東西講清楚到能讓機器執行，剩下的那些講不清的，就留給藝術、留給幽默、留給凌晨三點因為一個分母裡的小質數而突然看清的一整套理論。

- 手上有一個具體問題卡住的時候，去翻純理論的文獻。克努特寫不出字串匹配的高效程式，最後是庫克一個關於棧自動機的抽象定理給了他那把鑰匙。理論和實踐的距離，往往比你以為的近。
- 設計任何反饋機制之前，先想清楚你要的是哪一種結果。學習系統的獎勵函式決定了它學會什麼：只懲罰錯誤，它學會不輸；獎勵妙手，它學會冒險。克努特的井字棋收斂成了必和，他自己說得很明白。
- 做一個東西給別人用之前，先問一句“你怎麼知道它是對的”。Copilot 這類工具最好用在你能獨立驗證結果的地方，別用在驗證成本高於重寫成本的地方。
- 最佳化之前先測量。寫程式碼時覺得最難的那幾頁，往往不是機器花時間最多的地方。Fortran 編譯器八成時間在讀註釋卡，這個事實只有跑起來才知道。
- 給自己的程式碼寫給人看的部分。檢驗標準很簡單：一年後你還能不能輕鬆讀懂。做不到，就重寫。
- 每天先做清單上最不想做的那件事。拖不會讓它變簡單，只會讓你忘掉當初的思路。
- 把“不無聊”當成一項要練的技能。覺得一件事沒意思，多半是自己還沒找到看它的角度。
- 試錯是二分查詢。不要因為某個方向流行就走進去，也不要因為競爭激烈就繞開。想清楚自己有沒有那個直覺，然後動手試一次，答案會比任何規劃都清楚。
