計算機系統002 - 數值運算

SniperPan發表於2017-06-16

寫在開頭,本篇的唯一主題是二進位制計算,其他都是鋪墊。為了便於閱讀和管理,將單獨開一篇作為系列文章目錄,位置如下。

目錄

1. 傳統進位制

1.1 十進位制

當人類進化穩定開始衣食足而知禮節時,通常情況下使用最多的工具是雙手。雙手十指,隨身攜帶,遇到要計數時,自然會就近原則,伸出雙手開始掐手指。

計算機系統002 - 數值運算
甲骨文十進位制

1.2 斤兩

到了貨幣時代,買賣不僅要計數,還要計量。量有量綱,簡稱單位。舊時中國有官職“司馬”,糧秣管理時需要稱重,因此執著了統一度量衡。因此舊時斤也稱“司馬斤”,一司馬斤為十六司馬兩,簡稱一斤十六兩,自然“半斤八兩”。1930年《中華民國度量衡法》仍採用十六兩一斤的演算法,一斤500g,一兩為十六分之一斤,即31.25g。1959年《關於統一計量制度的命令》中說明由於兩這算麻煩,一律改為十兩一斤。

1.3 曆法

隨著交易範圍的擴大(或是任何一項需要多人蔘與的專案),為了避免浪費較多時間在集結這件事情上,出現了曆法。

指定曆法之前,要確定的是地球繞太陽公轉一週要365.24天,月球繞地球公轉一週要29.53天,365.24/29.83 = 12.37。

目前使用的公曆源自西元曆法,它是從羅馬時代凱撒時期制定下來,當時定的每個月有30天,與眾神有關的5個月額外增加一天,二月每四年閏月多一天,每百年不閏。當然這不可能是憑空想出來的,而是當時的天文學、地理學等學科有所突破,人們對地球自轉、公轉有所認知的結果。至於後面月份天數出現變化並不重要,總之雛形已定。

無獨有偶,在東亞地區也有一種曆法,叫做農曆(也稱陰曆、黃曆)。農曆有配合太陽陽光的二十四節氣,有根據塑望月為基準的月曆(十五月圓),有以迴歸年為基準的歲。同樣的,農曆也是依照天文資料計算而來,在清初時期,還有西方傳教士參與修訂《時憲書》。

1.4 時刻

我曾努力思考,為什麼時間是60進位制的,60這個數既不想888那麼喜慶,也不想13那麼邪乎,何德何能就佔據了時刻這麼重要的位置?
後來我瞭解到,天文觀測中,需要對天體的位置進行標定,在一個或半個圓周面上標定出若干位置,為了便於定位,就需要將圓周進行等分。等分時,公約數越多的數字越適合作為進位制的單位,當然也不能太大,而60就恰好符合這兩個條件。60有12個因素,分別為1、2、3、4、5、6、10、12、15、20、30、60,且2、3和5還是質數。60進位制的數可以被較多數整除,也就可以分成多個不同的時間長度,如15分鐘為一刻。

這一套,在農曆中依然有體現,六十一甲子,天干配地支呈60對,迴圈往復。

計算機系統002 - 數值運算

1.5 小結

標題明明是數學運算,我卻扯了半天幾斤幾兩、幾時幾分,為什麼?
因為要先建立一個前提,進位制的發明是基於應用環境的。很多資料在介紹二進位制時,總止步於二進位制適合計算機計算。為什麼適合?憑什麼適合?計算機這麼厲害,不能直接按十進位制算麼?
那麼下面我就告訴你,為什麼計算機必須使用二進位制計算。

2. 數值表示

2.1 數值表示的侷限

首先不得不承認,世界上沒有兩片完全相同的葉子。也就是說,當我們想通過擺兩片葉子、兩塊石頭、兩根手指來說明數量為2的時候,我們並沒有想象中那麼較真,我們並沒有嚴格限定兩件物品必須完全一致才能代表數量2。換言之,在數值表示時,適當的抽象是可以被接受的

為了方便表示促進交流,在接受實物表示數量的基礎上,我們做了進一步抽象,用虛擬的、概念的數字表示數量。這就是為什麼生活中可以將大把鈔票交給銀行,只換來幾個數字變化也能讓人深感欣慰的源泉。

不過很抱歉,任何試圖描述物體長度、重量、體積等數值表示都是經過美化的,畢竟大家都承認測量誤差是客觀存在的,更何況世界上還有一條測不準原理,所謂的數值表示也只是自我催眠對事物已有所瞭解。既然只能用數值近似表示某一物體的實際情況,那麼也就沒有誰敢拍胸脯保證某一數值就是物體實際情況。

換成人話,也就是今天我不能在測量了某一電池電壓值為5V就敢言之鑿鑿其電壓值一定為5V,因為說不定下一秒它就是5.0000001V,在下一秒就變成了4.9999999V。也許很多人覺得這一點點誤差我可以接受,那我想問一下,如果銀行告訴你,你賬戶裡有50萬,等你取的時候卻告訴你,不好意思,數值表示僅供參考,在你取錢的這一秒,賬戶上少了幾塊錢是否可以接受?再嚴重點,導彈發射時給的座標同樣有精度限制,是否可以接受因為精度導致發射時座標便宜一毫米而波及了你?

數值表示,是數值運算的根本。無法精確表示,何談精確運算,更別提產出精確結果。結果不精確、不可靠,那運不運算又有什麼意義?

2.2 求精不求多的二進位制表示法

類比電路

對於類比電路而言,要表示0~9十個數值可通過電壓、電流或者其他方式近似表示,如[-0.0001, 0.00001]表示0,甚至將容錯能力在提升一把,[-0.49999, 0.4999]表示0,只要將元器件質量控制好,不因時間、電場、磁場、溫度等複雜因素變化而變化,還是能勉強實現十進位制表示的。最多就是多弄一些保護電路、多供一些電以保證不會因為串聯引起分壓、多搞一些散熱設施保證大家散發的熱能即使撤走。最多,也就做一臺這樣的計算機,畢竟至少是有了。

計算機系統002 - 數值運算
ENIAC

ENIAC包含了17468個真空管、7200個晶體二極體、1500個繼電器、10000個電容器,還有大約五百萬個手工焊接頭。它的重量達27噸(30英噸),體積大約是2.4m×0.9m×30m(8×3×100英尺),佔地167平方米(1800平方英尺),耗電150千瓦[11][12](導致有傳言說,每當這臺計算機啟動的時候,費城的燈都變暗了[13])。
ENIAC有20個帶符號的十位累加器,它們使用10的補碼錶示方法,每秒可在它們和數字源(例如另一個累加器,或者常數傳送器)進行5000次簡單加減操作。

但對於ENIAC,我想絕大多數人不要說是否買得起,交得起電費,我想要先考慮的是買房的錢。當然即使這樣,還是有土豪可以支付得起的,但最大的弊端,可能就是運算頻率實在有限,畢竟很多電子元器件都是機械式的,要想對一個機械開關每秒鐘做幾千甚至幾G次開合,這就不太現實了。

數位電路

慶幸的是,人們發明了半導體。半導體元器件體積更小,一些特殊的元器件比如二極體、三極體甚至不用燈絲加熱來運作。同樣一個三極體,現在我們只要這麼一小片位置即可。

計算機系統002 - 數值運算
三極體

但這樣還不夠,有人希望可以做的更小,反正外層都是包裝和引腳,電子實質上是在半導體和導線間穿梭,不如去掉外殼,直接做一些模組。比如這個:

計算機系統002 - 數值運算

比如這樣:

計算機系統002 - 數值運算

但是積體電路有一個問題,裡面的電子元器件密集,各元器件本身體積有非常小,如果對這樣一個積體電路加以高電壓,那麼燒燬是在所難免的了。可是如果只是用低電壓,比如幾十毫伏,在這種情況下,仍然要保證數字0~9表示的足夠精確,那對元器件本身的要求就十分之高了。不僅要能工作,還要能抗干擾,不因外界任何變化而影響自身電壓電流。這幾乎是做不到的,哪怕能做到,良品率也是極低的,畢竟生產環境本身都存在諸多不確定因素的影響。

這種代價的前提下,是否還有意義堅持使用十進位制數值運算?答案是沒有。

其實完全可以換一種思維,做選擇和判斷題時通常更難的是選擇,如果是不定項選擇題,那就更難了。同樣的,區分一個電壓到底應該歸類成4V還是5V,遠比判斷到底有沒有電壓要不準確的多。判斷電壓有沒有無非兩種結果,要麼有,要麼沒有。管他誤差大不大,不通電自然沒有電,表示為0,通電了就是有電錶示為1。至於什麼23456789的,完全可以組合01表示出來,畢竟十進位制裡面也分個十百千(10的N次方,N從0開始)位,這裡來個2的N次方(N從0開始)做單位也說得過去啊。

這就是為什麼計算機裡面非要用二進位制,而不是十進位制來做數值表示的原因。不是不想,是不能

3.數值運算

計算機之所以稱為計算機,首先是要能計算。數學中最基本的是四則運算,再往上配合什麼正弦、餘弦、正切等等完成複雜運算,我們這裡不深入數學,畢竟本人數學很一般,就說說計算機怎麼用二進位制完成四則運算。

要知道,計算機不通電就是一堆廢鐵,通電了也不過是一堆會電人的廢鐵。且先不講作業系統原理之類的,單說一個加法器(事實上減法、乘法、除法均可通過加法器實現,只不過效率有所差異),到底是如何工作的。

計算機系統002 - 數值運算

  • A, B 被加數
  • Cin 低位進位, Cout本位進位
  • S 縮寫自Sum,表示和

這個加法器是1bit的,它的運算規則如下:

  • S = (A + B + Cin) % 2 取模
  • Cout = (A + B + Cin) / 2 除以

事實上我們知道程式中通常會至少使用8bit來表示一個數值,比如ASCII碼錶。而所謂的全加器其實就是級聯多個1bit加法器完成工作,前一加法器的進位Cout作為下一加法器的Cin。

計算機系統002 - 數值運算

簡單加法器看起來實現也並不複雜,那我們來思考一個問題,資料從哪裡來?

3.1 資料從哪裡來

這裡講的資料來源不是問怎麼從鍵盤或其他裝置到加法器這一層,而是問如何從暫存器(這裡先說明下儲存功能本身要麼通過反饋電路保持住電訊號,如暫存器;要麼寫時轉成磁訊號,讀時再由磁轉換回來,如磁帶、磁碟。)到加法器的兩端?

這個過程叫做裝載,以0+1為例,換成組合語言來講,表示如下:

    MOV 0. eax
    ADD 1, eax複製程式碼

但是電子元器件並沒有靈性,他們不會知道何時該取裝載,何時該去做加法,也就是說,如果希望這個由電子元器件組成的團隊正常運作,就必須有統一秩序,正如曆法、時間的發明,而在計算機內部,這叫做時序。時序作為統一指令,當時序行進到0時,哪些元器件應該去裝載,當行進到1時,哪些元器件應該協同完成加操作。

完成加操作後,運算所得值同樣應儲存起來以備後續使用。

3.2 流水線:空間換時間

如上一小節所述,完成一次加法需要如下三個階段:

  • 裝載
  • 運算
  • 存值

假如現在需要做3個加法,如果依次執行,則需要9個階段。假設每個階段需要一個時序,那麼總共耗費9個時序。是否有方法可以縮減所需時序呢?答案是流水線%E3%80%82)。

流水線的核心是拆分步驟、模組化、並行執行。模組化帶來的代價是必須引入儲存器儲存每個模組的結果以實現資料對接,相比單個模組直接完成,每拆分一步,就需要多消耗一個暫存器。因此,實際上是拿空間的開銷增加換取時間上的節省,這在程式開發中很常見,甚至MMX、SIMD等多媒體指令集也是遵循這個思想加快資料處理速度。

計算機系統002 - 數值運算

4. 總結

本篇主要說明了計算機採用二進位制運算的緣由,以及涉及到的基本步驟。至於更多的如CPU終端、Cache等技術,將於後續作業系統相關篇幅中展開。總的來講,簡單加法器只會與暫存器產生關聯,本篇的目的也就只需要到這裡即可。

相關文章