補碼黑歷史
對於每個計算機專業的同學,剛開始都會接觸到二進制轉換、原碼、反碼、補碼的知識。
國內教材上是如下定義的:
原碼:最高位爲符號位,0代表整數,1代表複數,非符號位爲改數字絕對值的二進制表示。如127的原碼爲 0111 1111,-127的原碼爲 1111 1111。
反碼:正數的反碼與原碼一致;負數的反碼是對原碼按位取反(符號位不變)。如127的反碼爲 0111 1111,-127的反碼爲 1000 0000。
補碼:正數的補碼與原碼一致;負數的補碼是該數的反碼加1。如127的補碼爲 0111 1111,-127的補碼爲 1000 0001。
記住上述的定義和轉換方法,通過考試so easy。可是,如果做個有心人,難免會有兩點疑惑:1)爲什麼負數和正數的規則會不同,這和我們學習其他概念方式差別很大;2)補碼到底有什麼用,引入補碼本質是爲了解決什麼問題?
帶着上面的疑問,對比下國外的計算機教材的講解,國內的教材只寫結論,對技術產生的背景幾乎完全忽略,實際上是本末倒置。如果理解了補碼背景,徹底理解補碼並不太難。
爲什麼需要補碼
補碼是一個工程問題,它是爲解決特定工程問題而引入的。
對於8比特的二進制編碼,最多可以表示256個不同的值,如果沒有負數,我們可以用來表示0~255,如果有負數,我們可以分別表示-128~127。
計算機應該如何表示負數呢?
以4比特二進制數爲例,最多可以表示16個數,如下表,我們至少有三種方式表示負數:
偏移碼:
我們以二進制最大值1111對應十進制最大值8,二進制最小值0000對應十進制最小值-7,中間編碼進行線性對齊。
符號碼:
符號碼更直觀,固定使用最高位表示符號,0表示正數,1表示負數,非符號位的二進制數值爲要表達數字的絕對值。這種編碼相對更直觀,但是存在0和-0,所以表示範圍要少一個。
補碼:
0000表示0,以0爲中心,依次向上是每個數加1(1 = 0001、2 = 0010、3 = 0011);依次向下,每個數字減1(因爲只有4位,減法操作時向上借位),-1 = 0000 - 1 = 1111, -2 = 1111 - 1 = 1110, -3 = 1110 - 1 = 1101。
對比上述三種編碼優劣,偏移碼和符號碼對我們理解起來很容易,但是對硬件設計卻是個難題。對於A = B + C,硬件設計者需要理解B和C每一位代表的意義,設計規則相對複雜,而對於補碼,則非常自然,只存在一個規則。
特別需要指出的,計算機內部,並沒有設計減法器,對於A = B - C,編譯器會將其轉換成 A = B + (-C),加入C是整數,B - C在計算機內部,是直接B的補碼和C的補碼相加。
補碼對我們來說,比較難理解,爲方便換算,人們總結出上一節補碼的轉換方法,也就是我們在學習時記住的結論。
補碼的數學原理
我們繼續回到人類的世界,還是按10進制舉例,加入只有1位10進制,一共可以表示0個編碼,可以表示爲0~9,也可以表示-5~4。
按補碼思路,對應的補碼, -5 = 5,-4 = 6, -3 = 7, -2 = 8, -1 = 9 , 0 = 0, 1 = 1, 2 = 2, 3 = 3, 4 = 4。
如果計算 4 + (-2),4 + (-2) = 4 + 10 - 2 = 4 + 8 = 12 = 2。
實際上,補碼是向高位借了一位,然後和當前數值進行求和計算,由於計算機位數有限制,會進行截取,所以高位接過來的一位對要計算的數值結果並無影響。
在只能表示一位的10進制裏,A = B + C 、A = (10 + B) + C 、A = B + (10 + C)、 A = (10 + B) + (10 + C)結果是相同的,如果是負數,和10進行結合後的結果就是補碼。