「本節內容節選自下方 參考資料 1html
在討論「二進制」和「CPU 如何工做」以前,咱們先來討論一下咱們生活中最稀疏日常的 數字,咱們與之頻繁地打交道:一個約定的時間、一件商品的價格、一我的的身高....卻不多有人細細想過,這些數字是如何表達出來的?爲何你理所固然地把 1024
理解爲「一千零二十四」而不是別的含義?java
也許你從未想過,在這簡單的記數中,沉澱着人類的大智慧。python
早在數字的概念產生以前,人類就學會了使用樹枝、石子、貝殼等天然界隨處可見的小物件表示獵物的、果實的、部落人口的數量。好比在某個角落堆上一堆石子,每打到 1 只獵物,就扔 1 顆石子進去,每吃掉 2 只獵物,就從中取走 2 顆石子。他們並不在乎石子的總數,只是時不時地瞅一眼,心底大體有數。git
其實這是一種最樸素的記數方式,數學家稱之爲 一進制記數法(unary numeral system)。咱們把它符號化一下,好比用斜槓 /
來表示:程序員
1
就是 /
;2
就是 //
;4
就是 ////
;好像沒毛病,咱們平時掰手指用的就是這種記數法,但數字一大,場面就要失控了。github
爲了解決記錄大數的問題,因而咱們得發明一些其餘符號來表示更大的數值,好比用橫槓 -
表示 10
,用十字 +
表示 100
。那麼:面試
16
就是 -//////
;32
就是 ---//
;128
就是 +--////////
;漂亮....這種靠符號類型和符號數量表示數字的方法被稱爲 符值相加記數法(sign-value notation),古埃及和古羅馬用的都是它,只不過符號各不相同。緩存
古埃及的記數符號:less
1工具
10
100
1000
10000
100000
1000000
1024
在古埃及就寫做:
你會發現,符值相加記數法的一大優勢是,符號的順序能夠任意打亂,數字含義不受影響。我國藏族曾用石子表示 1
、木棍表示 10
、果核表示 100
、蠶豆表示 1000
、瓦片表示 10000
,那麼,當你把 1
顆蠶豆、2
根木棍和 4
顆石子胡亂地攥在手裏,別人依然知道它們是 1024
。
古羅馬的作法略有不一樣,他們對五進制情有獨鍾:
1
5
10
50
100
500
1000
I
V
X
L
C
D
M
這些符號沿用至今,想必你們(至少對前 3
個)都比較熟悉,許多鐘錶仍保留着使用羅馬數字的習慣,1~12
分別表示爲:I
、II
、III
、IV
、V
、VI
、VII
、VIII
、IX
、X
、XI
、XII
。你會發現,羅馬記數法是符值相加記數法的變種,由於它不光「相加」,還「相減」。這種方式就不容許符號亂序了,IV
和 VI
表示的是不一樣的數字。
那羅馬人何苦要使用這種更復雜的記數法呢?無非是爲了讀寫方便。一樣表示 9
,IX
比 VIIII
更簡潔。
其實有一種更好使的方法——用另一些列符號來表示符號的數量。好比用 A
表示 1
個符號,用 B
表示 2
個符號,以此類推,用 I
表示 9
個符號。
如此,上文表示 256
的 ++-----//////
就能夠寫做 B+E-F/
。你必定感受莫名其妙,這種寫法哪裏方便了。其實中文的數字表示就是這種形式,只不過咱們用得太習慣了,以致於沒有發現。
在中文中,個
、十
、百
代替了 /
、-
、+
,而 一
、二
、三
代替了 A
、B
、C
。256
就寫做 二百五十六個
,個
比較累贅,咱們一般把它省略了。
其實像日語、英語用的也一樣是這種記數法,簡潔、優雅。
美中不足的是,這種形式雖便於讀寫,卻不便於計算。中國古人爲算籌和算盤這類經典算具搭建起廣闊的舞臺,卻沒給筆算留出一席之地。想象一下,若是讓你把這些漢字寫在草稿紙上,列個豎式,你的心裏必定很是彆扭。
公元5世紀,印度數學家阿耶波多(Aryabhata 476–550)創立了如今普遍使用的 位值制記數法(positional notation/place-value notation),該記數法使用的主要符號,是同爲印度人發明的阿拉伯數字:0
、1
、2
、3
、4
、5
、6
、7
、8
、9
。
與符值相加記數法類比,位值制中的 1
、2
、3
代替的是 A
、B
、C
,那 /
、-
、+
呢?是 靠阿拉伯數字的位置來表示的。衆所周知,最右位至關於 /
,次右位至關於 -
。靠每一個位置上的數值來表示數字,故名位值制。
嚴謹的數學家用一種多項式高度歸納了位值制記數法的本質,在十進制中,這個多項式是這樣的:
這是一個 n
位十進制數,ai 就是第 i 位上的數值。爲便於直觀理解,舉個 1024
的例子吧:
因爲咱們熟悉了十進制,這樣費心費力的展開可能會讓你以爲可笑,但當咱們把它推廣到其餘進制時,這個多項式的價值就體現了出來。n 位 b 進制數的位值製表示:
1024
用二進制怎麼表示?
所以,1024
的二進制寫做 10000000000
。
除了最廣泛的十進制和計算機中的二進制,常見的還有七進制(如 1
周 7
天)、十二進制(如 1
年 12
個月)、十六進制(如古代 1
斤 16
兩)、六十進制(如六十甲子)等等,只要有意義,任何進制均可覺得你所用。
在上述的多項式中,若是 ai 或 b 的取值奇葩一點,就造成了 非標準位值制(non-standard positional numeral systems),這類記數法每每應用於專業領域,很難在平常生活中見到。好比標準位值制中的三進制 ai 的取值爲 0
、1
、2
,但在一種名爲平衡三進制(balanced ternary)的非標準位值制中,ai 取 -1
、0
、1
,蘇聯曾使用這種進制研發電子計算機。
至此,你對「二進制」應該會感受親切了些,它只是一種數制而已,本質上與咱們熟悉的十進制沒有很大的差異,咱們這一 Part 來稍微理解一下二進制。(至於電腦爲何使用二進制咱們在下一 Part 中介紹)
十進制中的那些基本運算原則,二進制中一樣適用,只不過須要稍加變幻而已,下面咱們分別就加、減、乘、除四則運算來介紹。
根據「逢二進一」規則,二進制數加法的法則爲:
0+0=0 0+1=1+0=1 1+1=0 (進位爲1) 1+1+1=1 (進位爲1)
例如:1101
和 1011
相加過程以下:
根據「借一有二」的規則,二進制數減法的法則爲:
0-0=0 1-1=0 1-0=1 0-1=1 (借位爲1)
例如:1101
減去 1011
的過程以下:
二進制數乘法過程可仿照十進制數乘法進行。但因爲二進制數只有 0
或 1
兩種可能的乘數位,致使二進制乘法更爲簡單。二進制數乘法的法則爲:
0×0=0 0×1=1×0=0 1×1=1
例如:1001
和 1010
相乘的過程以下:
二進制數除法與十進制數除法很相似。
例如:100110
÷ 110
的過程以下:
由於編碼規定。
以前咱們有說到,全部保存的程序和數據在計算機中都被描述爲 文件,也就是說咱們可以知道當前的數據集合被指望的用途是什麼,也就可以找到對應的 處理器 來正確處理當前的數據。
拿文字舉例,爲了讓一串 0
、1
可以表明特定的文字,人們規定使用一個字節中的七位來表達特定的文字, 這就是大名鼎鼎 ASCII (American Standard Code for Information Interchange) 碼,ASCll 碼可以表達 27=128 種字符(編碼從 0~127
),對於 26
個英文字母和一些經常使用的可打印字符,這徹底足夠了:
但是,世界文化是多元的,面對相似漢字這樣的象形文字,ASCll碼錶用起來天然是捉襟見肘。
窮則思變,一個字節不行,那就兩個字節,這就是大名鼎鼎的 Unicode 碼,不難看出,Unicode 碼有 216=65536 種表示方式,這樣就足以表達一些經常使用的字符了,值得一提的是,Unicode 碼算是在 ASCll 碼上的一種擴充,其第 0~127
個編碼字符與 ASCll 碼錶如出一轍。
這裏涉及一點點物理知識,話說好久之前,牛頓經過三棱鏡把白色的光分解成七種不一樣顏色的光,後來又經過各類實驗發現紅、綠、藍三種顏色的光是沒法被分解的,所以咱們就稱爲紅藍綠爲光的三原色。
至此人類已經知道了:能夠經過組合不一樣比例的紅、綠、藍三種顏色來得到各類各樣的顏色,那麼咱們就能夠在計算機上模擬了。如今的計算機,通常使用 32
位來表示顏色,32
位平分給四個份量,也就是每一個份量 8
位。
爲啥是四個顏色份量?
由於顏色模型中有一個 alpha 值,用來表示透明度,這一點咱們先不考慮。總之三種顏色,每一個使用 8
位來表示的話,咱們就可以表示 256 * 256 * 256 = 16777216
種顏色了,已經足夠基礎的使用了。
先來看一張圖片:
這張圖像的尺寸是 600px * 664px
(px 是一種圖片單位,中文名稱爲像素,你能夠暫時理解爲一個點)。咱們把它放大一下,以下圖所示:
看見了嗎?實際上,大部分圖像(你拍攝的照片、你掃描的圖片、你使用 iPad 畫的圖片等等...)都是位圖文件,位圖就是由像素點構成的,它就像是一個網格同樣,每一個格子裏面填一個顏色。(除了位圖外,還有一種圖是矢量圖,它描述的是形狀而非網格)
OK,我想你已經能理解圖像是由像素點組成的了(事實上咱們的顯示器也是),咱們只須要在編碼中附帶上一些額外的信息,例如圖像有多大的尺寸、時間、做者、顏色深度、是否支持透明度之類的就可以對圖像進行正確表示了。(視頻能夠簡單理解成一張張接二連三的圖片)
要讓顯示器正確顯示圖片或者視頻,只須要讓顯示器上每一個像素顯示特定的顏色就行了。
可爲何必定是二進制呢?使用人類習慣的十進制很差嗎?
計算機依靠電力工做,這也就意味着須要將數字信號映射到電信號,實現這種映射最簡單的方法是:
二進制在技術上最容易實現。這是由於具備兩種 穩定狀態 的物理器件不少,如門電路的導通與截止、電壓的高與低等,而它們剛好能夠對應表示 「1」 和 「0」 這兩個數碼。假如採用十進制,那麼就要製造具備 10
種 穩定狀態 的物理電路,而這是很是困難的。
爲何使用更復雜的數字系統是一個問題?
假設咱們使用三元(3 位數字)數字系統涉及計算機,若是咱們具備從 0 V
到 5 V
的電壓,那麼咱們能夠進行如下的映射:
看起來合理吧?可是,想象一下,我以 2.5 V
的電壓發送了一個數字。可是因爲電路中的一些噪聲,我在輸出端獲得 2.3 V
的電壓,所以將其視爲 0
。結果是?
有人給我發送了 1
,但我將其視爲 0
。數據丟失但是一個很是嚴重的問題。
使用二進制則可靠得多,因爲電壓的高和低、電流的有和無等都是一種 質的變化,兩種物理狀態穩定、分明,所以,二進制碼傳輸的抗干擾能力強,鑑別信息的可靠性高。
創建數字系統的目的是 僅在某些時間點測試開/關(二進制)值,這使電線(或其餘設備)有時間更換。這就是計算機系統有時鐘的緣由。
時鐘會週期性地進行信號的測量,圖中所示的 T1 和 T2 就是能夠測量信號的時間點。
時鐘利用全部這些時間點來保持同步。更快的時鐘意味着每秒能夠對電線進行更屢次測試,而且整個系統運行得更快。2 GHz
處理器每秒檢查二進制值 20
億次。在這些時間之間,容許值改變並穩定下來。處理器芯片速度越快,每秒能夠測試的次數就越多,每秒能夠作出的決策就越多。
數學推導已經證實,對 N
進制數進行算術求和或求積運算,其運算規則各有 N(N+1)/2
種。如採用十進制,則 N=10
,就有 55
種求和或求積的運算規則;而採用二進制,則 N=2
,僅有 3
種求和或求積的運算規則,以上面提到的加法爲例:
0+0=0,0+1=1 (1+0=1),1+1=10
於是能夠大大簡化運算器等物理器件的設計。
採用二進制後,僅有的兩個符號 「1」 和 「0」 正好能夠與邏輯命題的兩個值 「真」 和 「假」 相對應,可以方便地使用邏輯代數這一有力工具來分析和設計計算機的邏輯電路。
雖然在 1950 年代就造出了更加高效的三元計算機,但在效率和複雜度的取捨上,始終抵不過二進制。二進制仍然在當今世界中長期存在。
上面咱們瞭解到計算機以二進制的形式運行,它們只有兩種狀態:開(1)和關(0),爲了執行二進制計算,咱們須要採用一種特殊的電子元器件,稱爲 「晶體管」。暫時咱們把它理解爲一種開關吧,通電就打開,沒電流經過就關閉。
咱們知道,給電燈通上電,它就會亮:
因而,結合上開關,咱們就能搭建出最基礎的 與門 和 或門。
該電路的邏輯是:只有當 A 和 B 同時開啓時,LED 燈纔會亮,也就是認爲輸出 1,咱們能夠利用電信號來簡單模擬一下:
A
B
Y
0
0
0
1
0
0
0
1
0
1
1
1
該電路的邏輯是:當 A 或者 B 開啓時,LED 燈就會亮,也就是認爲輸出 1,咱們能夠利用電信號來簡單模擬一下:
A
B
Y
0
0
0
1
0
1
0
1
1
1
1
1
相似地,咱們能夠藉助更多的電子元器件來創造出基礎的 7
種邏輯門電路:
這裏須要特別提一下 異或門,咱們須要先知道有一種電子元器件能夠利用電氣特性對 輸入取反,也就是說輸入 1
則輸出 0
,輸入 0
則輸出 1
,那麼咱們就能夠 簡單模擬 出異或門邏輯電路(實際會更復雜些,這裏僅展現出異或的意思):
A'
和 B'
分別表示 A
和 B
開關的反值,從圖中咱們很容易知道只有當 A
、B
只存在一個輸入 1
時,整個電路纔會輸出 1
。
OK,上面咱們瞭解到咱們可以利用 "開關" 來模擬邏輯的運算,咱們接下來試着還原一個簡單的加法運算器是如何實現的:
僅需兩個門,就能夠完成基本的二進制加法運算。上圖是利用 logic.ly
建立的半加法器,A
、B
至關於使咱們計算的兩個數,最後一塊至關因而咱們的數顯芯片,它的功能是根據輸入顯示數字,從上到下的引腳(也就是圖中輸入的地方,一般咱們這樣稱呼)分別對應了 20=1、21=2、22=4、23=8 的輸入,沒有任何輸入時顯示爲 0
,若是 引腳 1
(對應 20=1)像上圖同樣有輸入,則顯示 0 + 1 = 1
。
咱們來理解一下上方的電路:
引腳 1
,顯示 數字 1
(相似於 1 + 0 和 0 + 1
);引腳 2
,顯示 數字 2
(相似於 1 + 1
);數字 0
(相似於 0 + 0
);所以,若是兩個都打開,則 XOR 保持關閉,而且 AND 門打開,得出正確的答案爲 2
:
但這只是最基礎的半加法運算器,不是太有用,由於它只能解決最簡單的數學問題之一。但若是咱們把它們兩個與另外一個輸入鏈接,就會獲得一個完整的加法器:
仔細思考幾遍,你就會得知這個三個輸入的加法器已經能夠計算 3
個二進制數字的加法運算了,咱們如法炮製,能夠經過鏈接更多的"進位"來使這個加法器可以運算更多的數,這固然也意味着這個計算鏈條更長。
大多數其餘數學運算均可以加法完成。乘法只是重複加法,減法能夠經過一些奇特的位反轉來完成,而除法只是重複減法。而且,儘管全部現代計算機都具備基於硬件的解決方案以加快更復雜的操做,但從技術上講,您可使用完整的加法器來完成所有操做。
如今,咱們的計算機只不過是一個計算器,它記不住任何內容也對輸出沒有任何操做,上述電路只是接了一個顯示單元而已。
上面展現的是一個存儲單元。它使用了大量的 NAND 門,而且在實際生產中,根據存儲技術的不一樣,它們可能會大不相同,但其功能是相同的。
您給它一些輸入,並打開「寫」位(Write
輸入 1
),它將把輸入存儲在單元內。這不只是一個存儲單元,由於咱們還須要一種從中讀取信息的方法。這是經過一個使能器完成的,該使能器是「存儲器」中每一個位的「與」門的集合,全部位都與另外一個輸入(即「讀取」位)綁定在一塊兒。寫入和讀取位一般也稱爲「設置」(set
)和「啓用」(enable
)。
上面整個存儲單元都包裹在所謂的寄存器中。這些寄存器鏈接到 總線,總線是圍繞整個系統運行的一束電線,並鏈接到每一個組件。即便現代計算機也具備總線,儘管它們可能具備多個總線以提升多任務處理性能。
每一個寄存器仍有一個讀寫位,可是在這種設置下,輸入和輸出是同樣的。這實際上很好。例如:若是要將 R1 的內容複製到 R2,則應打開 R1 的讀取位,這會將 R1 的內容壓入總線。當讀取位打開時,您將打開 R2 的寫入位,這會將總線內容複製到 R2 中。
寄存器也用於製做 RAM。RAM 一般佈置在網格中,而且導線有兩個方向:
解碼器採用二進制輸入並打開相應的編號線。例如,11
在二進制數中是 3
,即最高的 2
位數字,所以解碼器將打開最高的線路。每一個路口都有一個寄存器。全部這些都鏈接到中央總線以及中央寫入和讀取輸入。只有跨寄存器的兩條導線也都打開時,讀和寫輸入纔會打開,從而有效地容許您選擇要從中進行讀寫的寄存器。一樣,現代 RAM 要複雜得多,可是此設置仍然有效。
寄存器無處不在,是在 CPU 中移動數據並將信息存儲在 CPU 中的基本工具。那麼,是什麼告訴他們移動數據的呢?
時鐘是 CPU 核心中的第一個組件,它將按設置的時間間隔(以赫茲或每秒週期爲單位)關閉和打開。這就是您看到的最直觀的 CPU 速度指標。
時鐘具備三種不一樣的狀態:基本時鐘,使能時鐘和設置時鐘。基本時鐘將打開半個週期,另外一半關閉。使能時鐘用於打開寄存器,而且須要更長的時間才能確保數據被使能。設置時鐘必須始終與使能時鐘同時打開,不然可能會寫入錯誤的數據。
時鐘鏈接到步進器,步進器將從 1
到最大步數進行計數,並在完成後將自身重置爲 1
。時鐘還鏈接到 CPU 能夠寫入的每一個寄存器的 AND 門:
這些 「與」 門還鏈接到另外一個組件的輸出,即指令解碼器。指令解碼器接受 SET R2 TO R1
之類的指令,並將其解碼爲 CPU 能夠理解的內容。它有本身的內部寄存器,稱爲「指令寄存器」,該寄存器存儲了當前操做。它的精確程度取決於您正在運行的系統,可是一旦解碼,它將打開正確的設置並啓用正確寄存器的位,這些寄存器將根據時鐘觸發。
程序指令存儲在 RAM(或現代系統中的 L1 高速緩存,更靠近 CPU)中。因爲程序數據與其餘全部變量同樣都存儲在寄存器中,所以能夠隨時對其進行操做以在程序中跳轉。這就是程序經過循環和 if
語句獲取結構的方式。跳轉指令將指令解碼器正在讀取的存儲器中的當前位置設置到其餘位置。
如今,咱們對 CPU 工做原理的有了一些基本的瞭解。主總線跨越整個系統,並鏈接到全部寄存器。完整的加法器以及其餘一系列運算都打包在算術邏輯單元或 ALU 中。該 ALU 將與總線創建鏈接,而且還將具備本身的寄存器來存儲正在操做的第二個數字。
爲了執行計算,將程序數據從系統 RAM 加載到控制部分。控制部分從 RAM 中讀取兩個數字,將第一個數字加載到 ALU 的指令寄存器中,而後將第二個數字加載到總線上。同時,它向 ALU 發送指令代碼,告知其操做方法。而後,ALU 執行全部計算,並將結果存儲在另外一個寄存器中,CPU 能夠從該寄存器中讀取該值,而後繼續該過程。
「
- 本文已收錄至個人 Github 程序員成長系列 【More Than Java】,學習,不止 Code,歡迎 star:https://github.com/wmyskxz/MoreThanJava
- 我的公衆號 :wmyskxz,我的獨立域名博客:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!
很是感謝各位人才能 看到這裏,若是以爲本篇文章寫得不錯,以爲 「我沒有三顆心臟」有點東西 的話,求點贊,求關注,求分享,求留言!
創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!