一般計算機系統中討論二進制的編碼問題涉及到的有:原碼、反碼、補碼,這裏簡單探討一下他們之間的關係。編碼
原碼與反碼spa
原碼是最早被提出的一種編碼方式,使用最高位表示符號(0表示正,1表示負),其他位表示數值。原碼存在一個問題,就是天然界中 +0 和 -0 是相同的,但 +0 的原碼是 0b00,而 -0 的原碼是 0b10,這樣 0 出現兩種編碼方式。blog
反碼是從原碼到補碼的過渡階段,對於任意一個整數 n ,它的反碼:內存
反碼一樣沒有解決 0 編碼格式不惟一的問題,但它只是一箇中間過渡;基礎
模數與補數循環
補碼是系統使用的編碼形式,在介紹補碼前,須要瞭解一下模數和補數的概念。二進制
一般稱:方法
x % y = zim
爲 x 模 y,其中 % 是取模運算符,y 稱爲模數,z 稱爲 x 在模 y 下的補數。總結
咱們來看下面的時鐘,當前指向 8 點,若是隻考慮小時的話,那麼時鐘的模數就是12,對於當前指向 8 點的時針,假如咱們但願它走到 6 點,則至少有兩種方法:
1. 8 + (- 2) = 6
2. (8 + 10) % 12 = 6
也就是說,若是定義順時針爲正,逆時針爲負的話,咱們能夠順時針轉動時針10個小時,也能夠逆時針移動時針2個小時,時針最終都會停留在6點上。
此時對於 -2 而言,它的補數就是 10,10 = 12 - |-2|,也就是說 一個負數的補數 等於 模數 減去 負數 的絕對值。之因此引入補數,是但願在一個相似鐘面這樣刻度有限、會出現循環往復的系統中,將減法和加法統一塊兒來,使得減法運算能夠一致的使用加法運算來處理。
補碼
在計算機系統內,補碼和補數的概念是一致的,那模數是什麼?以一個32位長度的整數而言,模數就是 2^32。就比如把一個圓盤分紅了2^32份,在這個系統中,最小值是 0 ,最大值是2^32-1,當2^32-1再向前走1位時,又回到了0。這種使用定長內存表示數值的方式使得補碼成爲合適的編碼方式。
回到以前的介紹上來,對於任意一個整數 n ,它的補碼:
對於一個負數,它的反碼是本身絕對值的原碼按位取反後加1,爲何?
前面已經介紹過,負數的補數等於模數減去其絕對值,即 32 位負整數 n 的反碼就是 2^32 - |n|,等於 (2^32-1) - |n| + 1。而 2^32-1 使用二進制表示恰好爲32位1,它減去 |n|,其實就是對 n 的絕對值按位取反了!
此外,對於 -0 的二進制原碼 0b100...00,其補碼爲 0b1111...11 + 1 等於0,而 +0 的補碼仍是0,從而避免了正負0的編碼結果不一樣的問題。
總結起來,正數和0的補碼就是其原碼,而知道了原碼、反碼、補碼之間的關係和補數是怎麼求的,就不難求得負數的補碼了。補碼之間一致地使用加法運算,即加上一個負數(減法),等於加上這個負數的補碼。而拿到一個負數的補碼,再對這個補碼進行一遍求補的運算,就能夠獲得原數的原碼了!
仍是因爲補碼成立的基礎,即便用定長的位數表示一個整數,也不難理解爲何補碼的運算不可避免的會存在溢出——負 + 負變正 或 正+正變負 的狀況了。