本文選自計算機科學經典著作《編碼:隱匿在計算機軟硬體背後的語言》。
語言只不過是一種編碼。
我們之中的許多人在學校裡至少都學過一門外語。所以我們知道,英文中的“cat”(貓)在其他語言中可以寫做gato、chat、Katze、KOIIIK或kátta。
然而,數字似乎並不是那麼容易隨文化的不同而改變。不論我們說什麼語言,或對數字使用什麼樣的發音,在這個星球上幾乎所有人都用以下方式來書寫數字:
1 2 3 4 5 6 7 8 9 10
這難道不就是數學被稱作“通用語言”的理由麼?
數字當然是我們平常所能接觸到的一種最抽象的編碼。當我們看到數字:
3
不需要立刻將它與任何事物聯絡起來。我們可能會聯想到3個蘋果或者3個別的什麼東西。但是當我們從上下文中得知該數字表示的是某個小孩的生日、電影片道、曲棍球賽的得分或蛋糕食譜中麵粉的杯數時,也能夠像認為它代表3個蘋果時一樣自然。因為數字最開始產生時就很抽象,所以對於我們來說,理解這樣一個問題會有一點困難。這個問題就是如下數量的蘋果:
並不一定要用符號“3”來表示。同樣可以用“11”來表示。
首先讓我們遺忘數字10原有的那些特性。大多數文明都是建立在以10為基數的數字系統上的(有的時候是以5為基數),這種情況並不奇怪。最開始,人們用自己的手指來計數。如果我們人類有8個或12個手指,那麼我們的計數方式就會和現在有所不同。英語中Digit(數字)這個詞同時也有手指、腳趾的意思,並且還有數字的意思,這並不是巧合。而five(五)和fist(拳頭)這兩個單詞的擁有相同的詞根也是同樣的道理。
在這個意義上,以10為基數或使用十進位制數字系統完全是隨意的。而且,英文中還對基於十的數字賦予了幾乎神奇的意義,並且給了它們特有的名字:十個一年是一個十年(decade);十個十年是一個世紀(century);十個世紀就是一個千年(millennium)。一千個一千就是一個百萬(million);一千個百萬就是一個十億(billion)。以下都是10的各次冪。
10^1 = 10
10^2 = 100
10^3 = 1000(千)
10^4 = 10, 000
10^5 = 100, 000
10^6 = 1, 000, 000(百萬)
10^7 = 10, 000, 000
10^8 = 100, 000, 000
10^9 = 1, 000, 000, 000(十億)
大多數歷史學家認為數字最初起源於對事物的計數,例如:人數、財產或商業交易的計數等。舉個例子,如果有一個人有四隻鴨子,用圖畫表示為:
後來,專門負責畫鴨子的這個人會想:“為什麼我非得要畫四隻鴨子?為什麼我不畫一隻鴨子再用劃線或其他事物來表示有四隻鴨子呢?”
然後直到有一天,出現了一個人,他擁有27只鴨子,這種劃線的方法就顯得很可笑了。
有人說:“必須想一種更好的方法。”於是一個數字系統就誕生了。
所有早期的數字系統中,只有羅馬數字沿用到了今天。我們可以在錶盤上、紀念碑和雕像的日期上、一些書的頁碼中,或者在條款的概述中看到羅馬數字,而令人最煩惱的就是電影的版權宣告(必須足夠快地破譯位於演職人員表末尾的“MCMLIII”才能知道這部影片是哪一年發行的)。
27只鴨子用羅馬數字表示為:
這個概念很容易理解:X表示10個劃線,V表示5個劃線。
沿用到今天的羅馬數字符號有:
I V X L C D M
這裡,字母I表示1,可以看做是一個劃線或者一根伸出的手指。字母V像一隻手,表示5。兩個V是一個X,代表數字10。L是50。C來自單詞centum,表示100。D是500。最後一個,M來自於拉丁文mille,意為1000。
儘管我們可能不會認同,但在很長一段時間內,羅馬數字被人們看做是易於加減的,這也是為什麼羅馬數字在歐洲作記賬之用一直沿用到今天。實際上,兩個羅馬數字相加的時候只不過是利用幾個規則將兩個數合併,這個規則是:五個I是一個V,兩個V是一個X,五個X是一個L,以此類推。
但是用羅馬數字進行乘法和除法卻很複雜。很多其他早期數字系統(像古希臘數字系統)和羅馬數字系統相似,它們在用於複雜運算方面同樣也存在一定的不足。儘管古希臘人發明的非凡的幾何學至今仍然是高中生的一門課程,但古希臘人並不是以代數而著稱的。
如今我們所用的數字系統通常被稱為阿拉伯數字,也可以稱為印度-阿拉伯數字系統。它起源於印度,被阿拉伯數學家帶入歐洲。其中最著名的就是波斯數學家穆罕默德•伊本穆薩•奧瑞茲穆(根據這個人的名字衍生出英文單詞“algorithm”,演算法),他在公元825年左右寫了一本關於代數學的書,其中就用到了印度的計數系統。其拉丁文譯本可追溯到公元1120年,它對加速整個歐洲從羅馬數字到阿拉伯數字系統的轉變有著重要影響。
阿拉伯數字系統不同於先前的數字系統,體現在以下三點。
阿拉伯數字系統是和位置相關的。也就是說,一個數字的位置不同,其代表數量也不同。對於一個數而言,其數字的位置和數字的大小一樣,都是很重要的(但實際上,數字的位置更重要)。100和1,000,000這兩個數中都只有一個1,而我們知道,1,000,000要遠遠大於100。實際上在早期的數字系統中也有一點是阿拉伯數字系統所沒有的,那就是用來表示數字10的專門的符號。而在我們現在使用的數字系統中是沒有代表10的專門符號的。另一方面,實際上阿拉伯數字也有一點是幾乎所有早期數字系統所沒有的,而這恰恰是一個比代表數字10的符號還重要得多的符號,那就是0。是的,就是0。小小的一個零無疑是數字和數學史上最重要的發明之一。它支援位置計數法,因此可以將25、205和250區分開來。0也簡化了與位置無關的數字系統中的一些非常複雜的運算,尤其是乘法和除法。
阿拉伯數字的整體結構可以以我們讀數字的方式來展現。以4825為例,我們讀做“四千八百二十五”,意思就是:
四千
八百
二十
五
或者,我們也可以將此結構以如下寫法寫出:
4825 = 4000 + 800 + 20 + 5
或者,對其進一步分解,可以將數字寫作:
4825 = 4 × 1000 +
8 × 100 +
2 × 10 +
5 × 1
或者,以10的整數次冪的形式來表示:
4825 = 4 × 10^3 +
8 × 10^2 +
2 × 10^1 +
5 × 10^0
記住任何數的0次冪都等於1。
一個多位數中的每一位都有其各自特定的意義,如下圖所示。這7個方格能代表0~9,999,999中的任何一個數字。
每個位置代表10的一個整數次冪。我們不需要一個專門的符號來表示數字“10”,因為我們可以將1放在不同的位置,並用0作為佔位符。
另一個好處就是,以同樣的方式將數字置於小數點右邊可以表示分數。數字42,705.684就是:
4 × 10, 000 +
2 × 1000 +
7 × 100 +
0 × 10 +
5 × 1 +
6 ÷ 10 +
8 ÷ 100 +
4 ÷ 1000
這個數也可以寫為不含除法的形式,如下:
4 × 10, 000 +
2 × 1000 +
7 × 100 +
0 × 10 +
5 × 1 +
6 × 0.1 +
8 × 0.01 +
4 × 0.001
或用10的冪的形式來表示:
4 × 10^4 +
2 × 10^3 +
7 × 10^2 +
0 × 10^1 +
5 × 10^0 +
6 × 10^-1 +
8 × 10^-2 +
4 × 10^-3
注意,10的冪指數是如何減小到0再變為負數的。
我們知道,3加4等於7。類似地,30加40等於70,300加400等於700,3000加4000等於7000。這就是阿拉伯數字的“閃光”之處。任何長度的十進位制數相加時,只要根據一種方法將問題分成幾步即可,而每個步驟最多隻是將兩個一位數字相加而已。這就是為什麼以前有人會強迫你記住加法表的原因。
從最上邊的一行和最左邊的一列分別找出要相加的兩個數字,這一行與這一列的交叉點就是所要得到的和。例如,4加6等於10。
同樣,當你想將兩個十進位制數相乘的時候,方法可能稍微複雜些,但是你仍然只需要將問題分解成幾步,做加法和一位數的乘法即可。在你的小學時代你一定也被要求必須記住下面的乘法表。
位置計數系統的好處並不在於它有多麼好用,而在於對非十進位制的系統而言,它仍然是易於實現計數的。我們現有的計數系統並不適用於每種情況。以10為基數的數字系統最大的問題是它對於卡通人物沒有任何意義。大多數卡通人物每隻手(或爪子)只有4根手指,因此它們需要一個以8為基數的計數系統。而有意思的是,許多我們在十進位制數中所瞭解到的知識同樣適合卡通朋友們所鍾愛的八進位制計數系統。
圖 書 推 薦
▊《編碼:隱匿在計算機軟硬體背後的語言》
【美】Charles Petzold 著
左飛,薛佟佟 譯
永不褪色的計算機科學經典著作用最簡單的語言講述最專業的知識這是一本講述計算機工作原理的書。不過,你千萬不要因為“工作原理”之類的字眼就武斷地認為,它是晦澀而難懂的。作者用豐富的想象和清晰的筆墨將看似繁雜的理論闡述得通俗易懂,你絲毫不會感到枯燥和生硬。更重要的是,你會因此而獲得對計算機工作原理較深刻的理解。這種理解不是抽象層面上的,而是具有一定深度的,這種深度甚至不遜於“電氣工程師”和“程式設計師”的理解。
▊《labuladong的演算法小抄》
付東來(@labuladong) 著
GitHub 68.8k star的硬核演算法教程labuladong帶你挑戰力扣演算法題挑戰BAT等大廠Offer本書專攻演算法刷題,訓練演算法思維,應對演算法筆試。注重用套路和框架思維解決問題,以不變應萬變。