C語言——原碼、反碼、補碼、資料型別取值範圍
記得剛學C語言的時候,對應資料型別的取值範圍經常會有這樣的疑問:比如8位的二進位制補碼範圍為什麼是-128~127呀?為 什麼會差一個數呀?(以8位為例)
為了解釋這個問題,我們先來了解下幾個概念(原碼、反碼、補碼):
原碼:它是一種計算機中對數字的二進位制定點表示方法。原碼錶示法在數值前面增加了一位符號位(即最高位為符號位):正數該位為0,負數該位為1(0有兩種表示:+0和-0),其餘位表示數值的大小。它的優點就是簡單直觀,缺點就是不能直接參加運算,可能會出錯。例如數學上,1+(-1)=0,而在二進位制中00000001+10000001=10000010,換算成二進位制為-2。顯然出錯了。這也是為什麼計算機儲存方式不能用原碼錶示的原因。
反碼:正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。反碼是數值儲存的一種,但是由於補碼更能有效表現數字在計算機中的形式,所以多數計算機都不採用反碼錶示數。
補碼:正數的補碼與其原碼相同;負數的補碼是在其反碼的末位加1。在計算機系統中,數值一律用補碼來表示和儲存。原因在於,使用補碼,可以將符號位和數值域統一處理;同時,加法和減法也可以統一處理。此外,補碼與原碼相互轉換,其運算過程是相同的,不需要額外的硬體電路。
由上面我們可以知道,在計算機系統中,數值一律是用補碼來表示和儲存的。現在我們來解釋下,為什麼8位的二進位制補碼範圍是-128~127。
在原碼的情況下,8
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]補 + [1111 1111]補 = [0000 0000]補=[0000 0000]原
這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]補 + [1000 0001]補 = [1000 0000]補
-1-127的結果應該是-128, 在用補碼運算的結果中, [1000 0000]補
使用補碼, 不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示一個最低數. 這就是為什麼8位二進位制, 使用原碼或反碼錶示的範圍為[-127, +127], 而使用補碼錶示的範圍為[-128, 127],(可以說用[1000 000]來表示-128 的補碼,這也是人為的一種規定吧)。
總結如下:
1、負數補碼形式從10000001到11111111依次表示-127到-1。
2、用補碼錶示負數時:負數X用2^n - |X|來表示,其中n為機器的字長(模運算)
(關於補碼更詳細的解釋,以及模運算http://baike.baidu.com/link?url=S6y7Pupzmg6PO_vXo3JcWdTRtUriU82AI_tYVYLyaTX5MRMY98A1izQKdqUkD3ym1PV0XcrQYQGKbWLKYXOfwa#3)
當n = 8 時,[-1]補 = 2^8 - 1 = 1111 1111, [-127]補 = 2^8 - 127 = 1000 0001
[-0]補=2^8 - 0 = 00000000 在補碼錶示法中只有一種表示,即 0000 0000 ,跟 +0 一樣
3、[-128]補 = 1 0000 0000 - 1000 000 = 1000 0000
全部補碼形式:
-128 ~ -1 1000 0000 1000 0001 1000 0002 。。。。。。 1111 1111 共128個
0 ~ 127 0000 0000 0000 0001 0000 0002 。。。。。。 0111 1111共128個
恰好是256個編碼!!