1. 程式人生 > 實用技巧 >原碼、反碼和補碼

原碼、反碼和補碼

在這篇博文中,我希望能從數學的角度幫助你理解計算機中的補碼世界,並嘗試解釋以下問題:

  • 符號位為什麼是最高位,為什麼1 表示負,0 表示正?0 表示正,1 表示負,為啥不是 0 表示負,1 表示正?

  • 為什麼補碼 1000 0000 表示 -128 ?

  • 為什麼補碼能夠實現減法運算?

關於原碼、反碼、補碼的計算這裡就不贅述了,但是如果你對於原碼、反碼、補碼的計算還是通過一個數 -> 二進位制原碼 -> 正數不變,負數保持符號位,其他位取反 得反碼 -> 反碼+1得補碼

另外也有上面的3個疑問的話

我強烈建議你忘掉之前關於原碼、反碼和補碼的認知

我首先丟擲三個問題,希望你帶著這三個問題去閱讀,當你能給出這兩個問題的答案的時候,上面的3個問題也有答案了

  1. 同餘的定義和意義是什麼?
  2. 在4位系統中,怎麼去表示負數?
  3. 在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同餘

,它們的餘數就是3

在這個系統中,能表示的數只有「餘數」,錶盤上的數字都是被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~78~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 - 3030 - 50

看到了嗎?在這個補碼的世界裡,才不管你是怎麼分的,分成-128 ~ 127 也好,分成 -100 ~ 155 也罷,老子天然支援減法運算

4. 帶著補碼武功進入8位系統江湖中

為了幫助你融會貫通補碼這門武功,我決定帶著你闖蕩一遍8位系統的江湖。在這裡,不用管10,二進位制也好,16進位制也好,思想都是一樣的。

我們再來計算 109 - 99 - 109,記住,不要用 10 的機器碼,我們純用補碼的思想(也就是同餘)來搞事

到了這裡,是不是覺得補碼也就那麼回事了。


現在,你是不是可以自己解決開篇的三個疑問了呢?帶著同餘的思想去幹掉這三個疑問吧!!