原碼、反碼和補碼
在這篇博文中,我希望能從數學的角度幫助你理解計算機中的補碼世界,並嘗試解釋以下問題:
-
符號位為什麼是最高位,為什麼
1
表示負,0
表示正?0
表示正,1
表示負,為啥不是0
表示負,1
表示正? -
為什麼補碼
1000 0000
表示-128
? -
為什麼補碼能夠實現減法運算?
關於原碼、反碼、補碼的計算這裡就不贅述了,但是如果你對於原碼、反碼、補碼的計算還是通過一個數 -> 二進位制原碼 -> 正數不變,負數保持符號位,其他位取反 得反碼 -> 反碼+1得補碼
另外也有上面的3個疑問的話
我強烈建議你忘掉之前關於原碼、反碼和補碼的認知
我首先丟擲三個問題,希望你帶著這三個問題去閱讀,當你能給出這兩個問題的答案的時候,上面的3個問題也有答案了
- 同餘的定義和意義是什麼?
- 在4位系統中,怎麼去表示負數?
- 在8位系統中,怎麼做減法運算?
1. 環形系統、模、同餘
在一個環形系統中,能表示的數是有限的。例如在下面的錶盤中,你能表示的數只有0~11,大於等於12的數,會被捨棄一部分,再在錶盤上表示出來。
比如15點,在鐘錶上表現的是3。當錶針越過11的時候,又從0開始,直到3。如果在鐘錶的世界裡,要表示27呢?鐘錶上無法表示準確的數字,27在這裡只能被表示為3。準確地說,在超出這個系統極限值的時候,這個系統只能用「餘數」來計量
在這裡,所有被12除,餘數為3的數,都被歸為1類。在這裡,還有餘數為0、1、2...11的類
而15和27,稱為 15和27關於模12同餘
在這個系統中,能表示的數只有「餘數」,錶盤上的數字都是被12除後的餘數
我們可以這樣理解這個系統:這個系統將整數分成了12類——被12除餘0、1、2、3、4、5、6、7、8、9、10、11的類
我們來看看「什麼是奇數?什麼是偶數?」
偶數是被2除餘0的整數,奇數是被2除餘1的整數。
通過模2我們將整數分成了兩類:餘0和餘1的數,也就是偶數和奇數
回到我們的錶盤,通過模12,所有的整數也能被分成12類,分別是餘0、1、2、3、4、5、6、7、8、9、10、11的類
所有的整數對模12做取模運算,按照它們的餘數我們可以給它們分類。
\[1\ \text{mod} \ 12 = 1\\ 13\ \text{mod} \ 12 = 1\\ -11\ \text{mod} \ 12 = 1\\ -23\ \text{mod} \ 12 = 1\\ \]
1、13、-11、-23是同一類!
到這裡,我們可以給出第一個問題的答案了。關於同餘是這樣定義的:如果兩個數a、b除以模m,餘數一樣,就稱整兩個數關於模m同餘,記為
\[a \equiv b\ (\text{mod}\ m) \]
同餘的意義就是分類!
2. 計算機世界
很容易理解計算機實際上就是一個環形系統。我們以4位bit來看看
在這個系統中,我們怎麼表示負數呢?比如說 -2
?既然這是一個環形系統,結合同餘來看這個世界會變得極其容易。
根據同餘,-2
在這裡和14
是同一類!所以我們可以用 14
的機器碼來表示 -2
14
的機器碼是 1110
現在問題出現了,1110
原來就是表示正數的14的,現在又要表示-2。那麼當機器給我們這個二進位制的時候,我們到底是把它看做14還是-2呢?
我們有一種做法:就是把0
~15
個數分成了兩組,0
~7
的機器碼還是代表原來的0
~7
,8
~15
的機器碼錶示了-8
~-1
當我們採用了上述這種分法的時候,歡迎來到補碼的世界。這正是我們現在的計算機世界——補碼世界
我們分別算一下-8
~-1
的關於模16的同餘數以及同餘數的二進位制機器碼
這些表示是不是很熟悉?最高位的 1
表示負號,補碼 1111
轉反碼 1110
轉原碼 1001
= -1
。符號位 1
表示負數,0
表示正數,不是拍腦袋決定的,而是基於同餘的思想
說到底,補碼的世界就是同餘的世界啊!!!
到這裡,我們可以解釋負數在4位系統中的表示了。通過引入了同餘,將這個世界中一半的大數轉為了小數對應的負數
3. 8位系統中的減法運算
通過引入同餘/補碼,我們可以表示負數,可以只用加法器實現減法運算
在這個補碼/同餘的世界裡,原生支援減法運算!!!
很容易得到,在8位系統中,mod = 1 0000 0000 = 256
,負數的範圍是-128 ~ -1
,正數是0 ~ 127
來看兩個例子:
「例子1」: 30 - 70 = ?
記住這是一個補碼的世界,我們沒必要管原碼和反碼,讓它們見鬼去吧!!!
30
的補碼是0001 1110
,這個很順利,我們直接轉二進位制就行了,因為 30 三 30 (mod 256)
-70
有點波折,因為我們需要知道它佔用了哪個同餘數的機器碼,256 - |-70| = 186
。它佔用了186
的機器碼,也就是 1011 1010
兩個機器碼直接相加得到 1101 1000
。這是補碼!!直接轉是216。但是這個值大於127,我們知道這個數的機器碼被它的同餘數-40
佔用了
因為256 - |-40| = 216
「例子2」: 100 - 50 = ?
在這裡,我們嘗試進入補碼世界,但是不用二進位制表示,為了符合我們直觀
記住這是一個環形世界,306
在這個世界和 50
是一類。 306 三 50 (mod 256)
,50
的機器碼並沒有被佔用,所以最終的答案就是 50
總結一下上面兩個例子,在8位系統中,模是256。能表示的數是 -128 ~ 127
。超出這個範圍的數都會根據同餘被歸到其中的一類
為了說明補碼原生支援減法。我們想象一個8位系統,我們希望它能表示的數的範圍是 -100 ~ 155
現在計算 50 - 30
和 30 - 50
看到了嗎?在這個補碼的世界裡,才不管你是怎麼分的,分成-128 ~ 127
也好,分成 -100 ~ 155 也罷
,老子天然支援減法運算
4. 帶著補碼武功進入8位系統江湖中
為了幫助你融會貫通補碼這門武功,我決定帶著你闖蕩一遍8位系統的江湖。在這裡,不用管1
和 0
,二進位制也好,16進位制也好,思想都是一樣的。
我們再來計算 109 - 9
和 9 - 109
,記住,不要用 1
和 0
的機器碼,我們純用補碼的思想(也就是同餘)來搞事
到了這裡,是不是覺得補碼也就那麼回事了。
現在,你是不是可以自己解決開篇的三個疑問了呢?帶著同餘的思想去幹掉這三個疑問吧!!