《九章算術》,一本成書于東漢初期、匯總了中國先秦至漢代數學成就的著作。Python版本的《九章算術》,以編程的方式詮釋《九章》,通過《九章》學習編程。
簡練精致的文言、清晰明了的代碼,相輔相成、相合相融。“觀陰陽之割裂,總算術之根源”,“析理以辭,解體用圖”,用嚴謹的態度在計算機上再現古人之思,在古算法的闡述中體現計算機編程之想、之美。
最近有個 GitHub 項目火了 —— 文言編程語言 / wenyan-lang。
這一項目并不是簡單的將程序中的英文字符換成了中文,而是利用 NLP 的一些技術,將文言文程序語法轉換到 JAVAScript 或 Python 運行。
來看看 文言版的“Hello world” 怎么寫:
吾有一數。曰三。名之曰「甲」。
為是「甲」遍。
吾有一言。曰「「問天地好在。」」。書之。
云云。
運行:
問天地好在。
問天地好在。
問天地好在。
文言文編程肯定沒有 abc,改用甲乙丙:
吾有一數。曰三。名之曰「甲」。
有數五十。名之曰「大衍」。
吾有一言。曰「「噫吁戲」」。名之曰「乙」。
true/false 改為陽/陰,類型變成了“爻”:
吾有一爻。曰陰。名之曰「丙」。
if 判斷:
若三不大於五者。乃得「「想當然耳」」。若非。乃得「「怪哉」」也。
循環:
為是百遍。??云云。
恆為是。??云云。
乃止。
看了這些代碼,網友戲稱:照這樣下去,《九章算術》就是一本算法導論;《孫子兵法》就是一本安全攻防;《易經》大概是一本二進制逆向……
其實,國內還真的有人研究《九章算術》,并且以編程的方式詮釋這時隔千年的經典數學著作。
她就是timedot,真名胡潔,擁有近二十年的IT從業和管理經驗,擔任過開發、測試、配置、測試經理、QA經理、高級項目經理等多個職務,具備扎實的理論基礎和豐富的實戰經驗,使用過的編程語言有:PB、C、C++、Java、Perl、Python。
同時他也是一名熱愛傳統文化的程序員,遵崇“科學藝術本相通,科技人文可相融”的創作理念,將致力于為計算機科學注入更多的人文氣息。
“術”和“算法”
《九章算術》是我國現存的最古老的數學著作之一。據初步考證,《九章》大約成書于東漢初期,匯總了中國先秦至漢代的數學成就。
《九章》是一本問題集,以問答的形式,匯集并分析了當時人們在實踐中所碰到的數學問題。全書共計246個問題202術,按問題性質分為方田、粟米、衰分、少廣、商功、均輸、盈不足、方程、勾股9章,其中各章在解決實際問題時,都有明確的計算方法:“術”。
《九章》成書后,歷經眾人傳抄、刪改,時有變動。直至魏晉時代,劉徽為《九章》作注,基本成為流傳后世基本的定本。而后至唐代,李淳風等人為其補注后,該書成為了算術專科的主要課本。之后,此書傳習不絕。“九章”二字,也成了中國數學的代名詞。
為什么說《九章》中的“術”其實可以對應計算機科學中的“算法”呢?我們來看一個實際的例子——里田術。
“問題一今有田廣一里,從一里。問為田幾何?
答曰:三頃七十五畝。
問題二又有田廣二里,從三里。問為田幾何?
答曰:二十二頃五十畝”
什么意思呢?
簡單翻譯一下就是:
問題一,有一塊方形田地,長為1里,寬為1里,其面積是多少?
答:3頃75畝。
問題二,又有方形田地,其長為2里,寬為3里,其面積是多少?
答:22頃55畝。
古人的思想,其實和我們現代科技又是相通的,在計算機上,我們可以再現古人之思。
比如這段話,也可以用我們設計優雅、明確、簡單的編程語言Python來翻譯。
1、自定義函數
我們可以把里田術定義成自己的一個函數。函數定義包括函數的名字以及函數被調用時運行的語句序列集。下面是這個函數的源碼,如圖所示。
函數的第一行叫做header(頭),其余部分叫做body(體)。header以一個冒號結束,body可以包含任意數量的語句。body里的所有語句必須縮進,縮進可以選擇兩個空格、4個空格或一個tab,無論選擇哪一種,body中每一條語句的縮進必須一致、必須對齊。
函數的命名規則和變量命名規則一樣:字母、數字、下劃線是合法的,但第1個字符不能是數字。你不可以用關鍵字作為函數名,也應盡量避免函數名和已有的變量名同名。
提示
關鍵字是編程語言里事先定義的、有特別意義的標識符,例如:def是一個關鍵字,表示這是一個函數定義;return也是一個關鍵字,表示返回函數結果。
2、注釋
一個程序是用代碼這種形式語言編寫的,很密集,只看一部分代碼,經常很難弄明白這部分代碼是做什么的,以及為什么要這么做。
程序越大越復雜,閱讀理解就會越困難。所以,在程序中必須增加注釋,注釋采用自然語言對程序的功能進行描述。注釋以#標志開始,Python解釋器會將注釋標示為紅色,會忽略從#到行尾的文本(這部分文本Python解釋器不會執行)。
3、程序剖析
程序第一部分為兩條賦值語句,一句賦值ji_li(積里),一句賦值mu_shu(畝數)。第二部分是畝數轉換,第三部分連接字符串返回結果。
1.賦值語句
ji_li=guang*cong#廣從里數相乘得積里
mu_shu=375*ji_li#以三百七十五乘之,即畝數
第一條賦值語句將傳入的參數guang、cong相乘的結果賦值于變量ji_li。
第二條賦值語句將ji_li與375相乘的結果賦值于變量mu_shu。
2.畝數轉換
#1頃=100畝,畝數轉換成頃和畝
qing=int(mu_shu/100)
mu=mu_shu%100
mu_shu/100是將畝數轉換成頃,結果是一個浮點數,如375/100→3.75;int(mu_shu/100)調用了int()函數,將mu_shu/100的結果截取成整數,如int(3.75)→3,即頃的整數部分。
mu_shu%100是取模運算,%是一種算術運算符,用于取除法運算的余數,例如:375%100→75(即375÷100商為3余75,這個余數75就是%運算的結果),也即畝數轉換成頃后剩余的畝。
所以,上面兩句代碼的含義如下。
畝數(mu_shu)若為375,頃(qing)=3,畝(mu)=75,
也就是:375畝 = 3頃75畝
3.字符串連接
#連接成字符串并返回結果
jie_guo=str(qing)+'頃'+str(mu)+'畝'
returnjie_guo
這里的“+”是“字符串連接”運算符,用于把字符串連接起來。表達式str(qing) + '頃' + str(mu) + '畝'求值為一個新的字符串,這個新的字符串連接了4個字符串里的文本:str(qing) 、'頃' 、str(mu) 、'畝'。其中str(qing)、str(mu)調用了str()函數,將整數qing、mu轉換成了字符串。
“+”運算符要么是加法算術運算符,要么是字符串連接運算符。它所連接的值要么都是整數或浮點數,要么都是字符串,不能又有整數、浮點數,又有字符串。表達式str(qing) + '頃' + str(mu) + '畝',如果寫成qing+'頃' + mu + '畝',就會出錯。因為qing、mu是整數,而'頃'和 '畝'是字符串,整數和字符串之間不能進行“+”運算符操作。
賦值語句jie_guo = str(qing) + '頃' + str(mu) + '畝',把連接成的新的字符串賦值給了變量jie_guo。
return jie_guo 將jie_guo作為函數li_tian_shu的返回值返回
4、運行結果
在IDLE中輸入這個函數,最后輸入一個空行結束。完成這個函數定義后,我們可以調用它來解決里田術問題一、問題二,運行結果如圖所示。
li_tian_shu(1,1)解決問題一“廣一里,從一里”,也就是傳遞給函數的參數為:guang=1、cong=1,結果為3頃75畝;
li_tian_shu(2,3)解決問題二“廣二里,從三里”,也就是傳遞給函數的參數為:guang=2、cong=3,結果為22頃50畝;
讀九章學Python
作為中國數學歷史上經典著作,其中精妙的算法構思值得程序員學習。而這本書用Python語言來表述《九章》中的各種“術”、各種數學思想,也通過《九章》來學習Python語言、學習編程、學習算法思維。
通過學習《九章》各卷通用的計算方法,由淺到深覆蓋了Python的編程基礎。這些計算方法包括:
卷一方田:合分術、減分術、平分術、割圓術;
卷二粟米:今有術、其率術、反其率術;
卷三衰分:衰分術、返衰術;
卷四少廣:少廣術、開方術、開立方術;
卷六均輸:均輸術;
卷七盈不足:盈不足術;
卷八方程:方程術、正負術;
卷九勾股:勾股術。
在對各術的講解過程中,加深對上篇各種編程概念的理解,呈現各種編程技巧,同步提升Python編程能力。各術的講解包括:圖解、中文注釋、數學術語和程序代碼,程序代碼中包含對應的文言注釋,程序代碼的右邊批注代碼的編程技巧。每一個“術”的開始,都附有Python編程要點。