資料整理: jserv, weihsinyeh
你一定聽過圓周率
本文回顧
"The most powerful force in the Universe is compound interest." (宇宙中最強大的力量是複利)。 ── 愛因斯坦
歐拉數 (Euler's number,
人類自古以來就對未來充滿疑問:下一刻會發生什麼?人們發現有些變化的規律,當數學家從單純的計數問題 (即自然數系統的建立) 進入探討連續變化的領域時,他們需要一個新的工具來描述這種自然的、持續的變化,這便是歐拉數出現的契機。
存款餘額成為
若銀行改為每半年給付一次利息,並將付給你的利息自動轉為本金,下半年便能和本金一起生息 (下圖紅色圓圈):
存款餘額成為
再進一步,若銀行每 4 個月 (即
存款餘額成為
你或許會貪婪地推論:倘若銀行每分每秒都給付利息,是否會使存款金額趨近無窮大呢?試算如下:
1 | 2 |
2 | 2.25 |
3 | 2.37 |
5 | 2.488 |
10 | 2.5937 |
100 | 2.7048 |
1,000 | 2.7169 |
10,000 | 2.71814 |
100,000 | 2.718268 |
1,000,000 | 2.7182804 |
… | … |
一年約有
累積下來的利滾利餘額約為
這種趨近的極限即定義為
金融領域廣泛使用歐拉數來計算連續複利,公式如下:
其中:
例如,若你有 1,000 美元,以年利率 2% 的連續複利投資 3 年,最終金額為
當銀行年利率為
並加以求解,可得
單位是「年」,亦可近似計算
公元 1683 年,數學家 Jacob Bernoulli 首先研究複利頻率對本金增長的影響,發現上述極限的存在。然而,真正將此數深入研究並證明其無理性質的則是瑞士數學家 Leonhard Euler,他於公元 1748 年的著作《Introductio in Analysin Infinitorum》詳述該數的性質,後人遂以 Euler 之名將該常數命名為「歐拉數」。
人類對自然界的理解,最初依賴宗教與神話。然而,自文藝復興時代起,對時間的精確測量與數學分析逐漸讓人類意識到,自然界的變化並非隨機無序,而是遵循一定的規律,且可用數學表達。當伽利略透過水滴計時,觀察物體從比薩斜塔落下的運動,並發現加速度的恆定性時,人類正式踏上以數學和科學解析自然的道路。
在自然界中,許多現象的變化速率與其目前狀態成正比,例如:
這類現象可用微分方程描述:
其通解為指數函數:
其中的
這個展開式橫跨離散數學中的「階乘」與連續數學中的「無窮和」,使
在物理中的波茲曼常數 描述氣體分子在重力場中或一般熱平衡狀態下的能量分佈,表現為
在核物理學中,放射性衰變 (Radioactive decay) 描述不穩定的原子核自發性地轉變成其他種類原子核的自然現象。這種轉變遵循著明確的數學規律,也就是指數衰減定律 (Exponential decay law) ,其數學形式如下:
其中:
放射性原子核數量隨時間呈指數遞減
原子核的數量會隨著時間以指數方式減少,這意味著每經過一段固定的時間,剩下的原子核數量佔原本數量的比例都是相同的。當一個原子核透過放出輻射 (例如
幾乎所有原子序大於 82 的重元素 (如鈾、釷) 的原子核都會發生放射性衰變,而某些較輕元素的不穩定同位素,例如碳-14 (Carbon-14) ,也具備同樣的衰變行為。
圖片出處: Free Webinar: Choosing Optimal Bone Samples for Analysis
放射性碳定年法 (radiocarbon dating) 或
當生物死亡後,碳交換停止,生物遺骸即成為封閉系統。體內的
半衰期是描述衰變快慢的常用概念,符號為
半衰期
從上式可推導出:
亦即,衰變越快 (
我們知道放射性衰變遵循
試著從微觀角度來思考。考慮每個不穩定的原子核,它發生衰變是個隨機事件。但在一個很短的時間間隔
現在,考慮一大堆 (例如
其中負號表示
接著求解這個微分方程。利用變數分離法,將所有跟
積分結果為
由於
這個常數
於是常數
在上述推導與求解過程中,不僅解釋放射性衰變為何符合指數變化規律,也揭開
指數函數
這驗證上方的解,同時也突顯關鍵性質:
亦即,對指數函數
倘若我們將微分運算子
這與線性代數中的特徵值 (Eigenvalue) 和特徵向量 (Eigenvector) 的概念極為相似。對於一個矩陣
則
接著我們可類比:
於是,關係式
在這裡:
這種微分運算子與其特徵函數、特徵值之間的關係,不只是個有趣的類比,還揭露指數函數之所以特殊和重要的原因:在物理學和工程學的許多領域中,基本定律往往以微分方程的形式出現,而這些方程的解,常與特定「運算子」(例如
特徵函數通常代表系統的一種「固有」行為模式或狀態。例如,在振動系統中,它們可能代表特定的自然振動頻率;在量子力學中,定態薛丁格方程式
回到上述碳-14 衰變問題。
微積分的建立,正是透過對這種連續變化的嚴謹研究與描述。
延伸閱讀: e^(iπ) in 3.14 minutes, using dynamics
雖然在人口成長與利息複利等應用問題中,可用指數函數進行推演,但
John Napier [ˈneɪpiər], 1550–1617
公元 1614 年,John Napier 發表對數與對數表,而直到公元 1637 年,法國數學家笛卡兒才引入現代指數記號系統,也就是說,對數的出現,竟然早於指數的形式化定義。真正釐清二者之間的關係,則已是百餘年後的公元 1770 年,由歐拉首次明確指出:「對數乃指數的反運算」。
對數之所以先於指數而被發明,根本原因在於其應用價值:17 世紀的歐洲,隨著天文學與航海技術的發展,人們面對大量數值計算,亟需更有效率的處理方式,對數因應而生。在對數問世以前,天文學與航海領域高度依賴三角函數表來進行繁複的計算,這些表格詳列各角度對應的正餘弦值,精確至小數點後多位,於是數學家利用以下三角恆等式:
將二角的乘積轉化為和差形式,也就是著名的「積化和差公式」,提供間接執行乘法的方法,不過該方法步驟繁瑣,僅是計算
對數的誕生,汲取積化和差的主體想法,卻將其精煉為更通用、更易操作的數學工具。只要藉由
一張對數表足以大幅加速乘除與開根號等運算,其後演化出的對數尺,更是工程師必備工具,猶如現今理工科學生獲贈的科學計算器。
然而,當時的對數計算主要用常用對數 (底數為
Jost Bürgi 曾擔任天文學家克卜勒的助手,負責大量繁瑣的天文計算工作,受前人 Michael Stifel 研究等差與等比數列關係的啟發,Bürgi 發展對數概念,並於公元 1610 年左右完成對數表,但直到公元 1620 年才正式發表於《Arithmetische und Geometrische Progress Tabulen》(等差與等比數列表) 一書。
遠在蘇格蘭的 Napier 也展開類似的工作,他出身貴族,是愛丁堡附近 Merchiston 城堡的第八代地主,未曾有過正式的職業,但對天文與數學充滿熱情,完全獨立於 Bürgi 的成果。古希臘哲學家提出「自然」(φύσις) 的概念,認為萬物自然而然地變化,哲學家赫拉克利特引入 λόγος (英語: Logos) 一詞,表達自然變化背後所隱含的秩序與規律性。λόγος 原本含義廣泛,可指言語、演講、敘事、論理,或是原則與法則。在哲學語境中,它逐漸轉化為代表萬物背後的尺度、分寸與比例,即強調萬物之間的數量關係。Napier 結合 Logos (比例) 與 Arithmos (數) 二詞並創造出 Logarithm 一詞,意指「比例之數」,也就是後來的「對數」。
Napier 最初構想的對數,與我們今日以指數函數為基礎的對數概念迥然不同,他不是從代數公式出發,而是以幾何的方式定義對數:透過二個以不同速度移動的質點,其行進距離之間的對應關係,來刻畫數量變化的比例性,如下圖:
圖中展示 Napier 定義對數的運動學模型:想像二個質點沿線段運動,上方 Moving
時間 | log( |
log( |
||
---|---|---|---|---|
0 | 速度等比例遞減 | 等速 | ||
1 | ||||
2 | ||||
3 |
這樣就可以發現如果一個質點以「等比例遞減的速度」移動,一個以「等速度」移動。兩者之間的距離關係就是
接下來看這段在〈指數與對數發展史簡介〉中的描述。
〈指數與對數發展史簡介〉乙、對數的發明 二、Napier對數
Napier 引進對數的方法並不像前面所說的那麼代數化,他的方法是幾何式的。下面我們來介紹他的定義方法 : 取二線與 ,令 之長為 。動點 沿 由 點移動至 點,動點 沿 由 點移動至 點。 點的初速度為 ,而在位置 時的速度為 。 點 上保持等速,其初速度也是 ,假設兩個動點同時出發,某段時間後兩動點分別到達 與 的位置,他定義 為 的對數。
示意圖 :
分析上面的話得到下面的資訊 :
如果 P 跟 Q 兩點的初速度都是
接下來把質點
第
因為
(距離)
用兩個向量相減的計算得出 :
最後再把示意圖中位置
雖然現在透過對數的原理知道一個質子當前速度為
圖中展示 Napier 定義對數的運動學模型:想像二個質點沿線段運動,上方 Moving
Napier 歷時近二十年編製出史上第一份公開發表的對數表,於公元 1614 年發表其鉅作《Mirifici Logarithmorum Canonis Descriptio》(對數奇妙表的說明),該書甫一出版,便在歐洲科學界引起廣泛關注,倫敦數學家 Henry Briggs 在公元 1615 年前往愛丁堡拜訪 Napier,他們一致認為,對數的使用不應僅限於三角函數表的計算需求,更可延伸至一般十進位數的運算。
Briggs 改以 10 為底的對數,這便是「常用對數」。Briggs 後來成為劍橋大學聖約翰學院院士與牛津大學薩維爾幾何學教授,他以現代化的記號與計算方法,構造出更實用的常用對數表。公元 1624 年,克卜勒親自編輯並補充出版 Napier 的對數表,使其更適合用於天文與數學領域。Napier 與 Briggs的合作成果,成功將對數從單一的天文計算工具擴展為通用的數值分析方法。正因如此,數學家拉普拉斯讚嘆:「對數的發明得以簡化計算,相當於延長天文學家的壽命。」
數學家在編撰對數表的過程中,面對繁瑣的計算步驟,意識到若採用以下形式作為底數:
可顯著簡化計算。Napier 採用的底數近似於
或許讀者會好奇,當初 Napier 為何要選擇如此特別的對數底數?事實上,這是為了提高對數表在計算上的實用性。若底數選擇得太大,則對數表的資料密度 (即計算精度) 將變得稀疏,導致許多數字在表中找不到適合的對數值,內插誤差便難以控制,嚴重影響對數表的效能。
舉例來說,若以
因此,我們想尋找一個理想的底數,其性質是當指數以固定幅度增加時,原始數值不會呈倍數暴增,而是以穩定、近似線性的方式成長。換言之,新的問題是:能否將乘法導致的等比變化,轉換為加法產生的等差變化?
我們假設存在某個底數
儘管
此時,左側的變化是每次乘以固定倍數
然而,絕大多數底數並不具備這種特性。若
數學家如何克服上述問題,從而建立以 10 為底的對數表呢?
根據換底公式:
只要選定一個適合的底數,並針對該底構造出一份覆蓋範圍廣泛的對數表 (例如從
初看之下,
為簡化真數的生成,我們可反向思考,取某個數的
接著嘗試以較小的底,如
0.0000 | 1 |
0.0001 | 2 |
0.0002 | 4 |
0.0003 | 8 |
0.0004 | 16 |
雖然表中的數值間距縮小,但仍增加過快,不適合廣泛採用。
直到我們選用更接近
0.0000 | 1.0000 |
0.0001 | 1.5000 |
0.0002 | 2.2500 |
0.0003 | 3.3750 |
0.0004 | 5.0625 |
我們從中發現規律:若底數形如
0.0000 | 1.0000 |
0.0001 | 1.0001 |
0.0002 | 1.00020001 |
0.0003 | 1.00030003 |
… | … |
0.9999 | 2.71787413941… |
1.0000 | 2.71814592682… |
這樣的表格同時具備二項優點:對數和真數皆呈均勻遞增,計算上只需重複乘以
Bürgi 正是採用該方法。要計算出
其中
換言之,構造高精度對數表的訣竅,在於選擇形如
接著我們用現代的數學語言來選擇
為了觀察當底數趨近於
這些近似來自以下二項式展開:
其中忽略高階項是因為
設
在極限情況下,當
為了展現上述極限行為,我們可用先前案例中的極小值
這些近似函數幾乎與自然對數函數
圖一:
圖二:
為更嚴謹地刻劃這樣的關係,以下探討函數
對於
簡化得:
當
接下來對
為滿足初始條件 (例如
這條推導路徑顯示,當底數趨近
換言之,我們已成功從「將幾何級數近似為算術級數」的出發點,建構出自然對數的定義基礎。這也說明 John Napier 當初選擇底數極接近
Napier 在微積分尚未成形的時代,獨力以二十年反覆運算與觀察,建立早期的對數表,並在過程中觸及
在十七世紀微積分萌芽的年代,介於 Napier 與牛頓、萊布尼茲之間的數學家,逐步將
延伸閱讀: 對數與約翰.納皮爾 (John Napier)
費馬 (Fermat) 在公元 1636 年之前就已推導出
於是人們自然聯想到:
在公元 1649 年以前,二位耶穌會會士 Grégoire de Saint-Vincent 與 Alphonse Antonio de Sarasa 研究雙曲線
惠更斯 (Christiaan Huygens) 是 17 世紀科學革命的重要人物,橫跨數學、物理、天文、工程與哲學等多個領域,堪稱一代巨擘。受到 Grégoire de Saint-Vincent 的影響,惠更斯在探索等軸雙曲線的過程,串起 Napier 發明的對數與 Grégoire de Saint-Vincent 發現的幾何結構之間的關聯。
作為物理學家,惠更斯建立向心力定律,提出動量守恆原理與光學中的惠更斯原理;作為天文學家,他發現土衛六 (Titan)、獵戶座大星雲、火星極冠與土星環的結構;作為工程師,他改良望遠鏡鏡片設計,發明精密擺鐘與火藥引擎 (內燃機的雛形);作為數學家,他發展漸屈線理論,提出單擺周期公式,並被視為機率論的早期奠基者。
在上述對等軸雙曲線
等軸雙曲線
這類滿足乘積轉加法規律的函數,即為對數函數。惠更斯從此幾何積分觀點出發,辨識出以
關於自然對數的最早記錄,出現在 Nicholas Mercator 於公元 1668 年出版的《Logarithmotechnia》一書,推動自然對數的形式化和應用。在許多實驗與自然現象中,被觀察對象的變化率 (增減速率) 往往與其當下的數量成正比,例如前述的複利和投資獲利,而所謂「自然對數」中的「自然」(natural) 一詞,並非因例子取於自然界,而是數學家在建構這些模型時,發現以
延伸閱讀: 資訊科技詞彙翻譯
到了 Johann Bernoulli (是 Jacob Bernoulli 的弟弟) 時代,積分問題進一步擴展為下式 (2) :
顯然可透過配方與換元法,將其化為與式 (1) 類似的形式。關鍵在於如何解方程
Johann Bernoulli 研究
另一方面,在 Johann Bernoulli 求解下式 (3) 這個特例時:
發現透過巧妙的代換 (如涉及複數
式 (3) 的積分結果是
到了公元 1740 年,Euler 發現
這個指數形式滿足與
並在公元 1748 年最終提出著名的歐拉公式:
從 Johann Bernoulli 與 Euler 的研究中,我們不難發現,無窮級數的展開對許多函數而言都至關重要。儘管主要是使用冪級數展開,但更為人所知的泰勒展開和牛頓展開,在本質上只差若干系數或運算步驟,後者則在隨後的研究中獲得更廣泛的應用。
延伸閱讀:
回顧歷史後,我們來看
為何要如此定義呢?
在探究指數函數 (例如以 2 為底的
為理解這個底數的特殊性,我們比較常見底數如
二者的變化率皆與其函數值不一致,顯示無法滿足
亦即,函數
該結論可從指數函數的一般導數公式中推得。考慮
這顯示
唯一滿足此條件的底數就是
因此,
該特性使
應用鏈式法則可得其導數為:
因此,任意指數函數
換言之,所有指數函數皆可透過自然對數
因此,
至於「為何用
延伸閱讀:
牛頓在發展微積分的過程中,研究對數函數的性質,牛頓利用他發展的廣義二項式定理,推導出
這個結果是藉由對
雖然牛頓主要處理的是對數函數,但他意識到對數函數存在一個反函數:若
然而,在牛頓的時代,數學家著重於函數本身的級數表示及其作為對數反函數的角色,但不會特別關注或定義這個級數在
真正將自然常數
歐拉的級數收斂很快,便於精確計算
以下證明極限
證明思路
觀察
首先,證明一個不等式。對於任意滿足
該不等式成立的原因如下:
其中,第二個等式成立使用到因式分解
由於
兩側不等式乘上被乘數
移項並整理可得:
接下來,構造一個遞增數列。令整數
由於
這表示
最後,證明數列有上界 (upper bound)。指定
將其代入不等式 (5),可得:
兩邊平方,得到:
由於這對任意
綜合上述結果,我們已證明:
上述關係為單調有界數列收斂原理 (Monotone convergence theorem)的充分條件 (sufficiency),則根據單調有界數列收斂原理,該數列必然收斂,因此極限存在且等於一最小上界,則令該最小上界為
只要有極限,任何運算都能用加減乘除處理,就算如下方這樣的普通計算器 (calculator,並非運算能力更強的電腦 [computer]):
其中,自然對數特別容易計算,接下來我們將介紹一種方法,主要靠計算器「開平方」功能。
歐拉數的泰勒展開如下:
對於普通計算器來說,實在難以計算上方的無窮級數。我們換個思路:回顧函數
可見,最後面那一項極限和
根據指數函數的圖形:
我們可推想,若有某個
和式 (6) 比較,可得:
式 (7) 的左邊是對數,右邊是乘冪,離我們設定的目標仍很遠,接下來的關鍵想法是把指數式轉換成根式。
也就是把
例如,取
計算器顯示
若改算
可發現,當
至此,只要我們懂得利用反覆開平方,再結合極限的概念,就能在普通計算器精準地計算歐拉數和自然對數。
計算歐拉數
該方法的數學基礎源自組合數學中的錯位排列 (derangement):若一個排列中,所有元素皆未出現在其原本的位置上,則稱為錯位排列。例如,排列 312
是 123
的一個錯位排列,因為其中 1, 2, 3 都未位於原始位置;而 321
則不是,因為數字 2 仍然處於原來的第二個位置。其關鍵的特性是,當元素數量
其中
根據這個極限關係,我們可反過來利用機率實驗近似
我們該如何在 Minecraft 中模擬上述呢?可用遊戲中的「紅石」(Redstone) 系統來搭建自動化裝置:
在論文提及的實驗中,產生 647 次排列,其中有 238 次是錯位排列。根據上述公式,得到的
誤差僅約 0.00766%。不僅展示
展示影片: Approximation of e in Minecraft 及播放清單。
為高精度計算自然對數底
該級數具有快速收斂性,若期望小數點後達
為估算
藉由二分搜尋,可有效找到滿足上述條件的最小 mpz_t
) 與浮點數 (mpf_t
) 為基礎進行實作,主要流程如下:
calc(mpz_t a, mpz_t b, mpz_t p, mpz_t q)
計算 p
, q
為輸出參數)calc(a, m, p_L, q_L)
計算左半區間和 p
, q1
)calc(m, b, p_R, q_R)
計算右半區間和 p2
, q
)p
與 q
(此處 p
重用 q
重用 q_L
和 p_R
則用區域變數 q1
和 p2
):
mpz_mul(p, p, q); mpz_add(p, p, p2)
)mpz_mul(q, q, q1)
)mpz_t
) 執行精確的有理數運算,僅在最終計算完成後,才用 mpf_div()
將總和的 mpf_t
),從而減少浮點捨入誤差的累積GMP 浮點型別需指定位元精度,公式為:
因此,百萬位數需要約 3.3 百萬位元,即約 0.4 MB 記憶體。對一億位數則需約 33 MB。參考程式碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <gmp.h>
#include <math.h>
#include <time.h>
#include <stdint.h>
#define FILENAME "e.out"
#define PI 3.141592653589793238462643L
#define E 2.718281828459045235360287L
/* progress tracking */
typedef struct {
uint64_t count, total;
int8_t last_percentage;
clock_t start_time;
} progress_t;
/* Global progress tracker */
static progress_t prog = {0, 0, -1, 0};
/* Compute log factorial using Stirling's approximation */
static long double log_factorial(uint64_t n)
{
if (n <= 1) return 0;
return (logl(2.0 * PI) / 2.0 + logl(n) / 2.0 + n * logl(n / E)) / logl(10.0);
}
/* Binary search for number of terms */
static uint64_t terms(uint64_t digits)
{
uint64_t lower = 0, upper = 1;
long double f;
while ((f = log_factorial(upper)) <= digits) {
lower = upper;
upper <<= 1;
}
while (upper - lower > 1) {
uint64_t n = lower + (upper - lower) / 2;
f = log_factorial(n);
if (f > digits) {
upper = n;
} else {
lower = n;
}
}
return upper;
}
static void write_e(mpf_t e, uint64_t digits)
{
FILE *fp = fopen(FILENAME, "w");
if (!fp) {
fprintf(stderr, "Failed to open %s\n", FILENAME);
return;
}
/* Write header */
fprintf(fp, "Calculation of e to %llu digits\n\n", digits);
fprintf(fp, "e = ");
char *str = mpf_get_str(NULL, &(long){0}, 10, digits + 1, e);
if (!str) {
fclose(fp);
return;
}
/* Write first line with integer part and decimal point */
fprintf(fp, "%c.", str[0]);
for (uint64_t i = 1; i <= digits; i++) {
fprintf(fp, "%c", str[i]);
if (i % 10 == 0 && i != digits) {
fprintf(fp, " ");
}
if (i % 50 == 0) {
fprintf(fp, " [%6llu]\n", i);
if (i < digits) {
fprintf(fp, " ");
}
}
}
if (digits % 50 != 0) {
fprintf(fp, "\n");
}
free(str);
fclose(fp);
}
static void show_progress_bar(void)
{
if (prog.total == 0) return;
int percentage = (int)(100.0 * prog.count / prog.total);
if (percentage <= prog.last_percentage) return;
prog.last_percentage = percentage;
int width = 50;
int filled = (int)(width * prog.count / prog.total);
clock_t now = clock();
double elapsed = (double)(now - prog.start_time) / CLOCKS_PER_SEC;
double eta = (prog.total - prog.count) * (elapsed / (prog.count ? prog.count : 1));
printf("\r[");
for (int i = 0; i < width; i++) {
printf(i < filled ? "█" : " ");
}
printf("] %d%% (ETA: %.0fs)", percentage, eta);
fflush(stdout);
if (prog.count == prog.total) printf("\n");
}
/* Recursive calculation with memory optimization */
static void calc(mpz_t a, mpz_t b, mpz_t p, mpz_t q)
{
mpz_t m, p2, q1;
mpz_inits(m, p2, q1, NULL);
mpz_sub(m, b, a);
if (mpz_cmp_ui(m, 0) <= 0) {
mpz_set_ui(p, mpz_cmp_ui(a, 0) == 0 ? 1 : 0);
mpz_set_ui(q, 1);
} else if (mpz_cmp_ui(m, 1) == 0) {
if (mpz_cmp_ui(a, 0) == 0) {
mpz_set_ui(p, 2);
mpz_set_ui(q, 1);
} else {
mpz_set_ui(p, 1);
mpz_set(q, b);
}
} else {
mpz_add(m, a, b);
mpz_fdiv_q_ui(m, m, 2);
calc(a, m, p, q1);
calc(m, b, p2, q);
mpz_mul(p, p, q);
mpz_add(p, p, p2);
mpz_mul(q, q, q1);
}
prog.count++;
show_progress_bar();
mpz_clears(m, p2, q1, NULL);
}
/* Main calculation function for e */
static void calculate_e(uint64_t digits) {
uint64_t d = digits + 1;
uint64_t num_terms = terms(d);
uint64_t precision = ceill(d * (logl(10.0L) / logl(2.0L))) + 1;
prog.total = num_terms * 2 - 1;
prog.start_time = clock();
printf("Calculating e to %llu digits\n", digits);
printf("Terms: %llu, Precision: %llu bits\n", num_terms, precision);
mpf_set_default_prec(precision);
printf("Actual precision: %lu bits\n", mpf_get_default_prec());
mpz_t z, p, q, n;
mpf_t pf, qf;
mpz_inits(z, p, q, n, NULL);
mpf_inits(pf, qf, NULL);
mpz_set_ui(z, 0);
mpz_set_ui(n, num_terms);
calc(z, n, p, q);
mpf_set_z(pf, p);
mpf_set_z(qf, q);
mpf_div(pf, pf, qf);
printf("Writing result to %s...\n", FILENAME);
write_e(pf, digits);
mpz_clears(z, p, q, n, NULL);
mpf_clears(pf, qf, NULL);
}
int main(int argc, const char *const argv[])
{
uint64_t digits = 1000000ULL;
const uint64_t precision_max = (sizeof(long) == 4) ?
1292913975ULL : 5553023288523357111ULL;
if (argc == 2) {
digits = strtoull(argv[1], NULL, 10);
if (digits == 0 || digits > precision_max) {
fprintf(stderr, "Digits must be 1 to %llu\n", precision_max);
return 1;
}
} else if (argc > 2) {
fprintf(stderr, "Usage: %s [#digits]\n", argv[0]);
return 1;
}
calculate_e(digits);
return 0;
}
上述程式碼可在線性時間內完成小數點百萬位的精確計算,對記憶體需求有限,且透過進度條顯示,最終輸出名為 e.out
的檔案:
e = 2.7182818284 5904523536 0287471352 6624977572 4709369995 [ 50]
9574966967 6277240766 3035354759 4571382178 5251664274 [ 100]
2746639193 2003059921 8174135966 2904357290 0334295260 [ 150]
5956307381 3232862794 3490763233 8298807531 9525101901 [ 200]
...
讀者可指定更多有效位數進行運算。此外,由於 GMP 已針對大整數乘法實作 Karatsuba、Toom-Cook 與 FFT 最佳化,上方程式無須自行處理底層運算效率的議題。
延伸閱讀: 從尤拉數 e 到 Stirling 常數
標準函式庫中的 exp 通常能達到接近 1 ULP 的精確度,然而許多應用場景,如即時系統、訊號處理、機器學習或遊戲引擎等,通常更注重運算時間,且能接受略低的精度,於是就會運用標準函式庫以外的指數函數實作。
〈留意浮點數運算的陷阱〉以
為快速近似計算指數函數
透過此恒等式,我們將指數函數從自然底數
將輸入
其中
接著,我們將
於是:
運用極小極大逼近多項式 (minimax polynomial) 來估算
這裡的係數經過調整,可將最大相對誤差控制在
在 IEEE-754 單精度浮點數格式中,浮點數的記憶體配置如下:
符號位元 (1 個位元), 指數 (8 個位元), 尾數 (23 個位元)
一個 float 可視為:
我們要產生一個浮點數,滿足以下:
s
) 為 0e
) 設為 m
) 來自 於是可透過將整數
運算流程如下:
因此可得
對應的 C 程式碼:
#include <math.h>
#include <stdint.h>
#include <string.h>
/* Fast approximate exp(x), x ∈ [-87, 88], max relative error ≤ 1.73e-3 */
float fast_exp(float x)
{
const float LOG2_E = 1.442695041f;
const float A = 0.3371894346f;
const float B = 0.657636276f;
const float C = 1.00172476f;
float t = x * LOG2_E;
float fi = floorf(t);
float f = t - fi;
int32_t i = (int32_t)fi;
/* Polynomial approximation for 2^f */
float exp2_frac = (A * f + B) * f + C;
uint32_t bits;
memcpy(&bits, &exp2_frac, sizeof(bits));
bits += ((uint32_t)i << 23);
float result;
memcpy(&result, &bits, sizeof(result));
return result;
}
不難發現,程式碼不依賴成本高昂的的數學函式庫呼叫,如 expf 和 powf,唯一用到的函式呼叫是 floorf 以達成浮點數對整數的轉換,隨後可換成處理器對應的指令,在 x86 的 SSE/AVX 或 Arm NEON 都存在這樣的指令。主要的運算由乘法、加法與位移運算構成。
基礎實作針對單精度浮點數,進階的實作則針對倍精度 (double
),適合需要更高精度及較大範圍的科學或一般運算情境,可運用以下常見技巧:
以下逐項探討。
為了近似特定區域 (segment) 的數學函式,最常見的技巧是使用多項式來擬合 (Polynomial Fitting) 該函數的局部區間。我們的目標是找出適當的係數,以建構出近似於
不過,由於多項式函數的形狀與
方法一:SciPy 函式庫
利用 Python 的科學計算函式庫 SciPy 中所提供的 Levenberg–Marquardt algorithm 方法,透過梯度下降 (gradient descent) 來擬合多項式係數。
利用三次多項式進行曲線擬合,參見 exp.py
方法二:Sollya 極小極大多項式
使用專門針對浮點數函式近似而設計的數值工具 Sollya。Sollya 可產生極小極大多項式,此多項式的特性為最大化降低近似函數的「最大誤差」,理論上可提供最佳的近似效果。
以下用 Sollya 找出近似
display = decimal; Q = fpminimax(exp(x), 6, [|D...|], [-0.000001, 1.001]); Q;
display = decimal; Q = fpminimax(exp(x), 5, [|D...|], [-0.0039, 0.0039]); Q;
經由上述程式碼可獲得多項式的係數。其產生的多項式在區間
多項式近似只能保證在有限區間內的準確度,因此我們需要額外處理更廣的數值範圍。我們透過範圍縮減的技巧 (range reduction) 來處理這個問題。
利用指數函數的特性
對於 IEEE-754 倍精度 (double precision) 的浮點數,能表示的最大指數為
#define TABLE_MIN -710
#define TABLE_MAX 710
#define TABLE_SIZE (TABLE_MAX - TABLE_MIN + 1)
static double EXP_TABLE[TABLE_SIZE];
/* precomputed exp(i) */
__attribute__((constructor))
static void init_exp_table(void)
{
for (int i = 0; i < TABLE_SIZE; ++i)
EXP_TABLE[i] = exp((double)(i + TABLE_MIN));
}
注意 __attribute__((constructor))
是 GCC/Clang 的 C 語言擴展,指定 init_exp_table
函式在程式碼載入時期,早於 main
函式予以執行,若你不用 GCC 或 Clang 相容編譯器,應當在使用 fast_exp
函式前,先呼叫 init_exp_table
函式。
負數可藉由以下恒等式處理:
然而,實務上若透過條件分支 (branch) 處理,可能造成 CPU 分支預測失誤 (branch misprediction),導致效能下降。因此,更好的方式是將查表法範圍直接延伸至負數,如上述範例,從而避免分支指令的使用。
若要評估多項式近似函數的表現,我們可將近似值與實際值相減,計算近似函數的絕對誤差 (absolute error) 或相對誤差 (relative error),並將結果繪製成誤差圖 (error plot),以直觀評估近似函數在整個區間內的表現。
以下 C 程式目標是在實務中提供足夠的精確度與效能: (沿用上方 init_exp_table
函式和 TABLE_
開頭的巨集)
#include <math.h>
#include <stdint.h>
/* Improved fast approximate exp(x) */
double fast_exp(double x)
{
double i_part = floor(x);
double f_part = x - i_part;
/* Minimax polynomial approximation for exp(f), f ∈ [0,1) */
const double c0 = 0.28033708;
const double c1 = 0.425302;
const double c2 = 1.01273643;
const double c3 = 1.00020947;
/* Horner's method for polynomial evaluation */
double poly = c3 + f_part * (c2 + f_part * (c1 + f_part * c0));
int i = (int) i_part;
if (i < TABLE_MIN) return 0.0;
if (i > TABLE_MAX) return HUGE_VAL;
return poly * EXP_TABLE[i - TABLE_MIN];
}
透過 Horner 表示法,多項式計算效率大幅提升:
此方法運算量少,且易於轉換成中央處理器的 FMA (fused multiply-add) 指令,例如 Intel 和 AMD 都有 FMA。
延伸閱讀: A Fast, Compact Approximation of the Exponential Function
現代計算機普遍採用二進位系統,但這並非唯一的選擇。事實上,三進位計算機曾在歷史上留下珍貴足跡,並於近年重新受到關注。
1950 年代末至 1960 年代,莫斯科國立大學的研究人員設計出早期的三進位電子計算機「Сетунь」(英語發音: Setun) 與其後繼型號「Сетунь 70」。「Сетунь」這個名字來自莫斯科附近的一條河。「Сетунь」電子計算機的設計由數學家 Sergei Sobolev (С·Л·Соболев) 等人於 1956 年左右發起,目的是提供高性價比的計算資源給高等院校與科研機構。研究團隊在資源有限的情況下,設計出基於鐵氧體磁芯 (ferrite cores) 與半導體二極體 (diodes) 的平衡三進位計算機,其邏輯電路利用正電壓 (代表 +1
) 、零電壓 (代表 0
) 與負電壓 (代表 -1
) 表示 3 個狀態,這種設計一度被認為具有潛在的速度、功耗和可靠性優勢。
這台採用時序邏輯的機器配備快速乘法器,使用小型鐵氧體環記憶體 (ferrite ring memory) 作為暫存器/累加器,搭配磁鼓 (magnetic drum) 作為主要記憶體,提供 24 道指令,其中包含預留指令,原型機於 1958 年完成,經過測試後於 1960 年代初期小規模生產。儘管「Сетунь」據稱表現穩定、應用廣泛,甚至獲得國外關注,但由於未能契合當時蘇聯主流的二進位計算機發展規劃,該專案最終未能大規模發展。總共生產約 50 台,分佈於蘇聯各地,用於工程計算、工業控制與教學等。
1970 年,原團隊的部分成員推出改進的「Сетунь 70」機種,並建立更系統化的三進位運算結構,包括:
然而,由於缺乏持續的支持,「Сетунь 70」也僅生產極少量,三進位計算機的發展就此沉寂。「Сетунь」最關鍵的特點正是採用平衡三進位的對稱編碼
電腦科學家 Donald E. Knuth 在《The Art of Computer Programming》第 2 卷說:
"Perhaps the prettiest number system of all is the balanced ternary notation"
(也許所有數值系統中最優雅者,就是平衡三進位表示法)
這裡的 ternary 意思是三個的、三個一組的、三重的,也稱為 base-3,顧名思義,不是只有 0
, 1
, 2
,在 balanced ternary (平衡三進位) 中,就是 -1
, 0
, +1
等三個可能狀態,又可簡寫為 -
, 0
, +
。
這裡的 "ternary"指「三元的」或「以三為基底的」(base-3)。標準三進位使用
the ternary values as being "balanced" around the mid-point of 0. The same rules apply to ternary as to any other numeral system: The right-most symbol, R, has it's own value and each successive symbol has it's value multiplied by the base, B, raised to the power of it's distance, D from R.
(三進位數值圍繞中點平衡分佈。其規則與其他數值系統相同:最右邊的符號 R 代表其自身的值,往左每個符號的值需乘以基數 B 的 D 次方,D 為該符號與 R 的距離)
一項用來度量進位系統效率的指標是「基數經濟性」(radix economy),它試圖量化表示給定範圍數值所需的「成本」,通常定義為基數
倘若我們暫時忽略位數
對於固定的數值範圍
我們可藉由微分找出
令導數
下圖基於
該圖顯示,雖然
計算
由於
平衡三進位使用
平衡三進位採用與二進位相似的位置表示法概念,但其關鍵優勢在於負數表示極為簡便:只需將正數表示式中所有非零的 trit 反轉 (亦即 +1
變 -1
,-1
變 +1) 即可得到其負數。
bal3
)由上可知,在平衡三進位中獲取一個數的負數,只需簡單地將所有非零 trit 進行符號反轉,無需像二進位那樣進行位元反轉再加
其負數
這種對稱性意味著正負數使用統一的規則表示,無需像在二進位系統中區分 signed
和 unsigned
類型。
平衡三進位不僅能一致地表示整數,也可用於表示分數 (近似浮點數) 。以下是十進位 0.2
的一個平衡三進位近似表示:
如同十進位的
如何近似表示十進位 0.8
呢?利用 0.8 = 1 - 0.2
及平衡三進位的簡易負數轉換特性:
上述近似計算,顯示平衡三進位中小數運算的對稱性。
接著,我們評估平衡三進位在計算負數時的效率。比較二進位 (採用二補數系統)與平衡三進位。以十進位數值 114
為例,求對應的負值:
10001101
10001110
(結果)若要量化這份差距,主要差異在於二進位的二補數所需的 +1
遞增操作。假設單個位元或 trit 的反轉時間相當,則平衡三進位的優勢在於省去加法步驟。n 位元二進位數加 1 時,發生進位傳播的平均位數期望值
當
平衡三進位的思想在現代人工智慧領域,特別是大型語言模型 (LLM) 的技術演化上,重新獲得關注。2023 年 10 月,Microsoft 研究院發表〈BitNet: Scaling 1-bit Transformers for Large Language Models〉,初步探索極低位元量化的可行性。隨後在 2024 年 2 月,該團隊發表影響更廣的〈The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits〉,正式提出 BitNet b1.58 方法,並釋出對應的開放原始碼專案 BitNet。此方法正是採用平衡三進位
BitNet b1.58 的特點及其體現的平衡三進位優勢,首先在於其三元權重 (Ternary Weights) 的量化策略。此方法將傳統以浮點數 (如 FP16 或 BFloat16) 表示的模型權重,透過縮放與閾值判斷,映射到 -1
或 +1
會引入顯著誤差,並破壞模型內在的稀疏性;而平衡三進位允許這些權重被精確量化為
這種三元量化直接帶來顯著的計算效率提升和能耗降低。在 LLM 中佔據主導地位的矩陣乘法 (
該手法與 2016 年的 BinaryConnect 和 IBM TrueNorth 等低精度類神經網路概念相呼應。這些研究早已證明:即使將權重量化為 1 位元,神經網路仍能正常訓練與推論。不過 BitNet b1.58 採用的平衡三進位在訊號能量與資訊表示上找到理想平衡點。此外,雖然是高度量化,
從神經科學的視角來看,平衡三進位的 -1
可視為抑制性神經元 (inhibitory neuron) 的輸出訊號,+1
則代表興奮性輸出,而 0
則表示未觸發。實際神經元的行為當然更為複雜,它們不依賴時鐘同步運作,並可整合訊號強度與時間累積效應 (如多個突觸電位的整合) 。脈衝的頻率與時間分佈也能影響神經訊號強度,這與我們從視覺感知中所見到的亮度與色彩變化不無關聯。儘管目前的類神經網路模型尚無法完全模擬這些生物特性,然而像 Intel 的 Loihi 2 等神經形態晶片 (neuromorphic chips) 正逐步接近這種非同步、類比式的訊號處理方式。
根據 BitNet b1.58 的研究論文,其效能表現相當亮眼:在 30 億參數規模以上時,其模型性能已能接近 FP16 的基準模型;而相較於同等規模的 Llama 模型,700 億參數的模型能達成約 4 倍的推理速度提升和 7 倍的記憶體節省,並支援更大的批次處理量以提高吞吐率。
如此簡化的運算 (僅需加/減/忽略) 也開啟硬體實作的潛力,非常適合設計專用的硬體加速器 (ASIC 或 FPGA) ,猶如前蘇聯科學家在「Сетунь」電子計算機所投入的三進位硬體探索。
這些研究成果表明,源於對數值系統效率 (
延伸閱讀:
與歐拉數相關的數學定理和公式極為豐富,遍佈於數學與科學的多個領域,以下列舉其中幾個。
「永無止境地循環下去的數字,和讓人難以捉摸的虛數畫出簡潔的軌跡,在某一點落地。雖然沒有圓的出現, 但來自宇宙的
該恆等式將 5 個基本常數:
為說明此公式的由來,先考慮一個粒子在實數線上運動,其位置為
這是一階線性常微分方程,其唯一解為
此解代表一種「自我增長」的行為:當粒子的位置越大,其變化速率也越快,呈現典型的指數成長。
接著將此觀念推廣至複平面,設
在複數表示中,向量旋轉
因此可建構以下運動方程:
此為複數微分方程,其解為
透過泰勒展開或解析法可知:
這正是歐拉公式的本體。若令
這不僅是個形式優雅的恆等式,也將指數函數、三角函數與複數自然地統整為一體。
在物理學中,
根據傅立葉分析,任何「行為良好」的週期函數
其中係數
即便是非週期訊號
其中
由此可見,複指數函數
在科學與工程中,面對複雜問題時,「分解」是一種主體策略。傅立葉分析正是基於此思想,將複雜函數或訊號分解到一組更簡單、具有普適性的「基底函數」上。為了有效達成這種分解,我們借鑒向量空間的概念,特別是「正交性」和「內積」。
在三維歐幾里得空間中,一組標準正交基底為
這裡,二個向量
任何一個三維向量
其中的係數
這是因為
因此,內積提供將向量「投影」到基底方向上,以獲得其分量 (係數)的方法。
傅立葉分析將這個概念從有限維的向量空間推廣到無限維的函數空間。我們可以將 (某些類型的)函數視為函數空間中的「向量」。為了定義函數空間中的「正交性」,我們需要推廣內積的概念。對於定義在
其中
現在,考慮傅立葉分析中扮演基底角色的複指數函數。令
這個積分在嚴格數學意義上不收斂,但在廣義函數 (或分佈)的框架下,其結果與狄拉克 δ 函數 (Dirac delta function) 相關:
狄拉克 δ 函數的性質是:當
有了這組正交基底,我們就可以將任意 (行為良好的)函數
而傅立葉逆轉換:
則表示原始函數
傅立葉分析的本質,就是將一個在時域 (time domain) 中描述的函數
延伸閱讀: 圖解傅立葉分析
「我認為質數的魅力在於無法說明它出現的秩序。每個質數都沒有因數,似乎隨意地嵌在數列之間。雖然數字越大,想要找出質數也就越困難,卻仍然無法依據任何已知規則來準確預測它們的出現。這種捉摸不定、難以駕馭的特性,對追求完美的博士而言,彷彿就是一種無法抗拒的誘惑。」
這段話出自小說《博士熱愛的算式》,凸顯質數既孤高又神秘,看似雜亂卻富含某種隱約的規律。人類對質數的探索已有二千多年,古希臘時期,歐幾里得以反證法證明質數的無窮多性,這是最早的論述,而既然知曉質數無窮存在,便產生新問題:前
十八、十九世紀,法國數學家 Adrien-Marie Legendre 和德國數學家高斯 (Gauss) 先後提出猜想:前
用以更精細描述質數的實際增長。這些近似式不完美,但都強調質數分布深受對數
歐拉曾為「質數數量」的研究奠下重要基礎。他考慮下列乘積:
其中
左邊針對全體質數的無窮乘積,右邊則針對全體自然數的無窮級數。當指數
1859 年,黎曼在成功把
宣示質數定理成立。Chebyshev 曾顯示若上述比值的極限存在,必為 1,並由此推得Bertrand—Chebyshev 定理 (Bertrand Chebyshev theorem):對任何自然數
經歷長期的純數論研究積累,質數的特性於 1970 年代末期發展成為現代公開金鑰密碼學 (public-Key cryptography) 的關鍵。公元 1977 年,Ron Rivest、Adi Shamir 與 Leonard Adleman 在其發表的論文〈A Method for Obtaining Digital Signatures and Public-Key Cryptosystems〉中,提出以其姓氏首字母命名的 RSA 公鑰加密演算法。該演算法建基於選取二個極大的秘密質數
質數分佈看似混沌,但質數定理揭示其宏觀規律:質數的平均密度可由以
延伸閱讀:Frans Oort 談質數
其中
其中的指數項
在物理學中,常態分佈的出現更具有深層意涵。例如,熱擴散方程的基本解即為高斯型 (即常態型) 分佈,這描述粒子在隨機熱運動下擴散的機率密度。該現象的隨機性來自於微觀層級上眾多獨立作用的累積,而其宏觀行為則收斂為常態分佈,這與中央極限定理完全吻合。事實上,在許多與隨機擾動相關的微分方程中,指數函數
接著思考常態分佈中為何會出現
至於
其中
這表示在二維或三維空間中,具有旋轉對稱性與軸向獨立性的隨機分佈,其機率密度會隨距離平方衰減,並自然形成以
常態分佈中
因此,
描述在固定時間或空間範圍內,隨機事件發生的次數。其機率密度函數為:
這裡的
泊松分布可看作是二項分布在次數
為什麼現實中常出現泊松分布?回顧其定義:若某事件在單位時間內平均發生
這個形式與
二者的結合意義不只在於形式上的巧合。考慮將時間細分為
當
進一步理解
這可理解為:每一小段時間內有極小的發生機率,整體隨時間累積出平均次數為
指紋識別晶片藉由數千個微型電容感測器生成指紋的拓撲圖,並針對每個像素點進行比對,裡頭也能見到泊松分布。
指紋可看作手指的紋路,而常見的感測方式主要可分為光學式感應器與電容式感應器二種,前者透過光源與感光元件組合,儲存手指輪廓所反射的光線變化,後者則是藉由半導體晶片,記錄皮膚表面不同部位所呈現的電荷分布、溫度梯度與壓力差異。以電容式感應最為常見,iPhone 5s 所採用的正是這種技術。
電容式指紋辨識模組的基本原理是,對每個像素點的電容感應顆粒預先充電到某一準位,當手指接觸感測器時,系統會檢測各像素點的放電電流。由於指紋的脊 (凸起) 與峪 (凹下) 會產生不同的電容值,放電速率亦隨之改變,藉此可區分出凹凸紋理的位置,從而重建出完整的指紋圖像。這些圖像資料會儲存於快閃記憶體中作為後續比對使用,辨識流程則包含:從指紋圖中提取特徵點、建立特徵向量,並將其轉換為數位訊號進行比對。
電容式設計薄而輕巧,適合用於行動裝置上,其成本較高,且感應元件易受到汗水或油脂影響,為了解決這個問題,感應器上會額外加裝保護層,例如 iPhone 5s 採用藍寶石玻璃覆蓋其指紋感測器以增加耐久性。這些像素點可視為獨立的伯努利試驗 (Bernoulli trial),每個像素點只有「是否誤配」的兩種結果。在試驗次數眾多、單次誤配機率極低的情況下,根據機率論的極限定理,這樣的重複伯努利試驗所導致的總誤配次數可近似為服從泊松分布。
設
亦即,系統可藉此計算某次比對中出現恰好
舉例來說,若系統估計正常狀況下雜訊造成的誤配次數為
這樣的尾部機率可作為安全門檻的參考,決定是否強制啟用第二道驗證。
以下用金融案例,解說泊松過程。
在日常生活中,我們經常會遇到排隊等候的場景,例如在銀行辦事時,客戶隨機到達櫃檯。那麼,若在某段時間內統計有多少人加入排隊?這類問題的數學建模可從最簡化的假設出發。
設
上述條件構成泊松過程的基礎假設。我們可數學化地寫為:
根據此,我們得到:
設
兩邊同除以
解得:
也就是
若允許
泊松過程的應用之一是建構隨機跳變的模型。不同於 Brown 過程 (連續變化),泊松過程適用於處理突發事件,例如資產價格突升、信用違約事件等。
在金融建模中,實際資產價格常會表現出「非連續、突變」的特徵,違反 Black-Scholes 模型中連續路徑的假設。此時,可將價格過程設為:
其中 1
展現資產收益率不連續的變化:
1 minute USDJPY April 14, 2015。取自: Donnelly, B. (2019). The art of currency trading: a professional's guide to the foreign exchange market. John Wiley & Sons.
這種模型被稱為跳躍擴散模型 (Jump-Diffusion Model),由 Merton 最早提出。這裡的連續成分來自指數函數
在結構化信用風險模型中,違約事件常用 泊松 過程建模。若以
這裡的
信用違約交換 (CDS, Credit Default Swap) 報價可反推市場對違約率的預期。在最簡模型中:
其中
以下圖表顯示 2010 年歐洲主權債務危機時,各國 CDS 溢價快速上升,市場即透過泊松跳變預期模型來估算違約風險:
Sovereign Credit Default Swaps (2010 年歐債危機)
泊松過程因其簡潔的機率結構與高度可解性,成為排隊理論、風險管理與金融數學中不可或缺的工具,而與歐拉數
我們身處的世界,本質是連續的。時間猶如河流般流淌不息,汽車的速度、放射性元素的衰變速率、電容器兩端的電壓等現象,都在時時刻刻發生著平滑而連續的變化。在數學上,我們習慣使用連續變數的函數及微積分來描述這一切,其中,微分運算子
然而,數位電腦的世界運作方式截然不同。它們的內部時鐘以離散的節拍跳動,透過類比數位轉換器 (ADC) 在特定的時間點進行「採樣」(sampling),並藉由數位類比轉換器 (DAC) 在特定時刻施加控制。電腦僅能在離散的時刻
工程師人員面臨的關鍵挑戰,便是如何運用這些離散的觀測結果,來理解、預測,甚至控制本質上連續運行的實體系統。Jack Crenshaw 博士在其於 embedded.com 發表的經典系列文章中,提出極具洞察力的數學工具,他巧妙地將其比作「羅塞達石碑」(Rosetta Stone):
此處
「羅塞達石碑」源於其在破解古埃及象形文字上的關鍵作用。石碑上刻有同一段內容的三種不同文字 (古埃及象形文、埃及草書、古希臘文) ,使得學者能夠相互對照,最終解開失傳語言之謎,開啟了現代埃及學的大門。Crenshaw 博士借此比喻,強調此方程如同石碑一般,扮演翻譯者的角色:它將描述連續系統動態的語言 (涉及微分運算子
「羅塞達石碑」的根基是泰勒級數,它根據函數
其中
將
在離散世界,電腦處理序列
這些運算子相互關聯:
這些關係為離散與連續的橋接提供操作基礎。
在連續世界,
英國物理學家和電子工程師 Oliver Heaviside 透過運算子微積分洞察,發現:
雙線性變換進一步實用化。設
這將連續傳遞函數轉換至離散域,廣泛應用於數位濾波器設計。
數值微分從離散資料估計導數。假設汽車巡航系統每
使用
為提升精度,使用後向差分:
其中
微控制器透過環形緩衝區儲存歷史資料,即時計算加速度,調整油門以保持平順駕駛。
數值積分求解常微分方程 (ODE)
假設音頻採樣率 44100 Hz (
亞當斯預測法提供高精度:
假設
羅塞達石碑
延伸閱讀:
整整二十年前,筆者因拜讀 Jack Crenshaw 博士於 embedded.com 發表的一系列文章而深受啟發,複習歐拉數