前230年 · 阿基米德窮竭法:圓周率緝拿案#
卷宗編號:Case-0230-Exhaustion|偵探:阿基米德(Archimedes)|地點:敘拉古
案發現場#
西元前三世紀的地中海世界,藏著一樁懸了數百年的奇案:圓,到底有多大。
埃及人說圓面積是直徑的八分之九再平方,巴比倫人取圓周率為 \(3\) ,《聖經》裡的銅海也暗示同一個粗糙數字。商人要算糧倉容積,工匠要造圓柱神廟,天文學家要量天體軌道,可是誰也說不清,圓周與直徑之比究竟是個什麼數。
更棘手的還有第二現場:敘拉古王懷疑金匠在王冠裡摻了銀。國王要真相,卻不准把王冠熔掉。一個是無限曲線的謎,一個是不許破壞證物的謎。兩樁案子,看似無關,卻指向同一個兇手——連續與無限。
阿基米德接下委託時,希臘幾何學只有直尺、圓規與歐多克索斯的比例論。他沒有代數符號,沒有小數點,沒有電腦。他唯一的武器,是邏輯。
偵查過程#
線索一:曲線抓不到,就用直線包圍它#
阿基米德的第一個推理轉折是:既然圓周是彎的、摸不著的,那就派兩隊「線人」從內外兩側夾擊。
他在圓內接一個正多邊形,又在圓外切一個正多邊形。圓周長 \(C\) 必定被夾在兩者之間。設圓直徑為 \(d\) ,內接多邊形周長為 \(p_n\) ,外切多邊形周長為 \(P_n\) ,邊數為 \(n\) ,則:
兩邊同除以 \(d\) ,就得到圓周率的上下界。邊數越多,包圍圈越緊。這就是窮竭法的靈魂:不直接追捕無限,而是用有限步步進逼,把誤差逼到牆角。
線索二:從六邊形出發,倍增邊數#
偵查從最好下手的地方開始:正六邊形。內接正六邊形邊長等於半徑,這是現成的突破口。
阿基米德用角平分線的幾何關係,把邊數一路倍增: \(6 \to 12 \to 24 \to 48 \to 96\) 。每倍增一次,就用勾股定理與比例關係更新邊長。設內接 \(n\) 邊形邊長為 \(s_n\) ,外切 \(n\) 邊形邊長為 \(t_n\) ,迭代關係可寫成現代形式:
他全程只用分數運算,硬是把開方的不精確性用不等式兩頭擋住。算到九十六邊形時,包圍圈終於收網。
線索三:收網數字#
經過冗長的分數圍捕,阿基米德宣布了數學史上第一份「數值誤差報告」:
換成小數,約為 \(3.1408 < \pi < 3.1429\) 。嫌犯 \(\pi\) 的活動範圍,被壓縮到寬度不到 \(0.003\) 的小巷裡。
| 邊數 \(n\) | 內接下界 | 外切上界 | 區間寬度 |
|---|---|---|---|
| \(6\) | \(3.0\) | \(3.4641\) | \(0.4641\) |
| \(12\) | \(3.1058\) | \(3.2154\) | \(0.1096\) |
| \(24\) | \(3.1326\) | \(3.1597\) | \(0.0271\) |
| \(48\) | \(3.1394\) | \(3.1461\) | \(0.0067\) |
| \(96\) | \(3.1408\) | \(3.1429\) | \(0.0021\) |
上表為現代換算值,阿基米德原著全用分數表述,但夾擊結構完全一致。
parallel 案件:王冠裡的銀#
另一頭,王冠案也在收網。阿基米德在浴缸裡靈光一閃:物體浸入水中減輕的重量,等於它排開的水重。設物體重為 \(W\) ,浮力為 \(B\) ,排開液體密度為 \(\rho\) ,體積為 \(V\) ,則:
金比銀重,只要把王冠與等重純金同浸水中,比較溢水量,摻假無所遁形。傳說他裸奔上街高喊「尤里卡」,正是這樁並案告破的瞬間。
理論定性:窮竭法的三條鐵律#
- 夾擊:構造可計算的上下界序列,而非猜一個近似值。
- 單調收斂:邊數增加時,下界遞增、上界遞減,絕不反覆。
- 誤差可證:每一步的誤差都有明確上界,這正是現代數值分析的祖訓。
結案報告#
阿基米德破了雙案。圓周率案中,他證明曲線量可以用直線序列任意逼近,開創了「數值逼近」的先河;王冠案中,他留下浮力定律,成為流體靜力學的起點。
此案的遺產極為深遠:
- 方法遺產:窮竭法是積分的雛形,兩千年後被牛頓、萊布尼茲 formalize 為微積分,又被馮·諾伊曼搬進電腦。
- 精神遺產:「給出近似值時必須同時給出誤差界」,這條規矩從本案一直沿用到今日的區間運算與驗證計算。
- 未竟線索:阿基米德沒有代數符號與極限語言, \(96\) 邊形已是人力極限。真正的「無限細分」自動化,要等到尤拉方法與電腦登場。
用現代眼光看,本案是計算模擬學的第零章:世界可以寫成幾何,幾何可以化為算術,算術可以一步步逼近真相。
證據與工具#
- 核心不等式:圓周率被鎖定在 \(3\frac{10}{71} < \pi < 3\frac{1}{7}\) 之間。
- 夾擊公式:內接周長 \(p_n\) 與外切周長 \(P_n\) 構成的雙序列,是最早的收斂性證明框架。
- 浮力公式: \(B = \rho V g\) ,靜水稱重法至今仍是密度量測標準。
- 手算工具:角平分定理、勾股定理、歐多克索斯比例論;全程分數運算,以不等式控制開方誤差。
- 可重演實驗:取圓直徑 \(d = 1\) ,用程式將邊數倍增至 \(n = 1536\) ,觀察上下界如何收斂到 \(3.1416\) 附近。
- 延伸閱讀:《圓的度量》、《論浮體》;後續案件直通牛頓運動方程,因為微積分正是窮竭法的合法繼承人。
補充:程式實作#
本文核心理論是雙側夾擊:圓周長必介於內接與外切正多邊形周長之間。 設圓半徑為 \(1\) ,內接正 \(n\) 邊形周長為 \(2n \sin(\pi/n)\) ,外切周長為 \(2n \tan(\pi/n)\) 。 兩者同除以直徑 \(2\) ,即得下界 \(L = n \sin(\pi/n)\) 與上界 \(U = n \tan(\pi/n)\) 。 邊數沿 \(6 \to 12 \to 24 \to 48 \to 96\) 倍增時,下界遞增、上界遞減,寬度單調收縮。 兇手 \(\pi\) 終於被逼進寬度僅 \(1.68e-03\) 的死巷,長達兩千年的圍捕在此收網。
執行指令:
python3 _code/-0230-archimedes_pi.py
實測關鍵輸出(本機真實執行結果抄錄):
n= 6: 下界 3.0000000000,上界 3.4641016151,寬度 4.64e-01
n=12: 下界 3.1058285412,上界 3.2153903092,寬度 1.10e-01
n=24: 下界 3.1326286133,上界 3.1596599421,寬度 2.70e-02
n=48: 下界 3.1393502030,上界 3.1460862151,寬度 6.74e-03
n=96: 下界 3.1410319509,上界 3.1427145996,寬度 1.68e-03
true pi = 3.1415926536,落在下界與上界之間
VERIFY lower96 = 3.141032(大於 $3.1408$ ,符合阿基米德下界)
VERIFY upper96 = 3.142715(小於 $3.1429$ ,符合阿基米德上界)
PASS
讀者可將邊數列延伸至 \(n = 1536\) ,觀察區間寬度縮小的速率,並對照真值 \(3.1415926536\) 計算誤差。
上述下界與上界均為程式以雙精度三角函數直接求值所得,未使用分數逼近,與原文分數表述互相印證。
完整程式如下:
# -*- coding: utf-8 -*-
"""0230 Archimedes 夾擊 pi(對應 wiki:計算模擬學 / 阿基米德窮竭法求 pi)
圓半徑=1:內接正 n 邊形周長=2n·sin(pi/n),外切正 n 邊形周長=2n·tan(pi/n),
故下界 L=n·sin(pi/n) < pi < n·tan(pi/n)=上界 U。
取 n=6,12,24,48,96(倍增),驗證 n=96 時 3.1408 < pi < 3.1429。
只用 numpy,固定種子。
"""
import numpy as np
np.random.seed(0)
ns = [6, 12, 24, 48, 96]
print(f"{'n':>5} {'lower=n sin(pi/n)':>20} {'upper=n tan(pi/n)':>20} {'width':>12}")
results = {}
for n in ns:
lower = n * np.sin(np.pi / n)
upper = n * np.tan(np.pi / n)
results[n] = (lower, upper)
print(f"{n:>5d} {lower:>20.10f} {upper:>20.10f} {upper - lower:>12.2e}")
lo96, hi96 = results[96]
print(f"true pi = {np.pi:.10f}")
print(f"96邊: 下界={lo96:.6f} (理論下界→pi), 上界={hi96:.6f}")
# 驗證數字:理論值 vs 實測
ok_lo = lo96 > 3.1408
ok_hi = hi96 < 3.1429
ok_bracket = (lo96 < np.pi < hi96)
print(f"VERIFY lower96={lo96:.6f} (>3.1408? {ok_lo})")
print(f"VERIFY upper96={hi96:.6f} (<3.1429? {ok_hi})")
print(f"VERIFY bracket: {lo96:.6f} < pi={np.pi:.6f} < {hi96:.6f} ? {ok_bracket}")
assert ok_lo, f"下界不夠緊: {lo96}"
assert ok_hi, f"上界不夠緊: {hi96}"
assert ok_bracket, "pi 不在夾擊區間內"
print("PASS")