一. 原碼, 反碼, 補碼的基礎概念和計算方法.
1. 原碼:
原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值. 比如如果是8位二進制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
第一位是符號位. 因為第一位是符號位, 所以8位二進制數的取值范圍就是:
[1111 1111 , 0111 1111]
即
[-127 , 127]
2. 反碼
反碼的表示方法是:
正數的反碼是其本身
負數的反碼是在其原碼的基礎上, 符號位不變,其余各個位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
3. 補碼
補碼的表示方法是:
正數的補碼就是其本身
負數的補碼是在其原碼的基礎上, 符號位不變, 其余各位取反, 最后+1 (即在反碼的基礎上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]補
[-1] = [10000001]原 = [11111110]反 = [11111111]補
二. 為何要使用原碼, 反碼和補碼
計算機可以有三種編碼方式表示一個數.
對於正數因為三種編碼方式的結果都相同:
[+1] = [00000001]原 = [00000001]反 = [00000001]補
但是對於負數:
[-1] = [10000001]原 = [11111110]反 = [11111111]補
機器可以只有加法而沒有減法
計算十進制的表達式: 1-1=0
如果用原碼表示:
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
讓符號位也參與計算, 顯然對於減法來說, 結果是不正確的.這也就是為何計算機內部不使用 原碼表示一個數.
如果用反碼表示:
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反
= [1000 0000]原
= -0
用反碼計算減法, 結果的真值部分是正確的. 而唯一的問題其實就出現在"0"這個特殊的數值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.
用補碼表示:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原
= [0000 0001]補 + [1111 1111]補
= [0000 0000]補
=[0000 0000]原
=0
這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原
= [1111 1111]補 + [1000 0001]補
= [1000 0000]補
=-128
注:-1-127的結果應該是-128, 在用補碼運算的結果中, [1000 0000]補 就是-128. 但是注意因為實際上是使用以前的-0的補碼來表示-128, 所以-128並沒有原碼和反碼表示.(對-128的補碼表示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的)
使用補碼, 不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示一個最低數. 這就是為什么8位二進制, 使用原碼或反碼表示的范圍為[-127, +127], 而使用補碼表示的范圍為[-128, 127].
(-1) + (-1) = [1000 0001]原 + [1000 0001]原
= [1111 1111]補 + [1111 1111]補
= [1111 1110]補 //負數原碼=補碼-1,再同位取反,符號位不變
=[1000 0010]原
=-2
因為機器使用補碼, 所以對於編程中常用到的32位int類型, 可以表示范圍是: [-231, 231-1] 因為第一位表示的是符號位.而使用補碼表示時又可以多保存一個最小值.