原碼、反碼和補碼之間的關係
- 機器數:一個數在計算機中的二進制表示形式, 叫作這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號。正數爲0, 負數爲1。
好比:十進制中的數 +3 ,計算機字長爲8位,轉換成二進制就是00000011。若是是 -3 ,就是 10000011 。那麼,這裏的 00000011 和 10000011 就是機器數。
- 真值:由於第一位是符號位,因此機器數的形式值就不等於真正的數值。爲區別起見,將帶符號位的機器數對應的真正數值稱爲機器數的真值。
例如:上面的有符號數 10000011,其最高位1表明負,其真正數值是 -3 而不是形式值131(10000011轉換成十進制等於131)
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
- 原碼:原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其他位表示值。
好比:若是是8位二進制:[+1]原 = 0000 0001 [-1]原 = 1000 0001 第一位是符號位.
由於第一位是符號位, 因此8位二進制數的取值範圍就是:[1111 1111 , 0111 1111]即[-127 , 127]。原碼是人腦最容易理解和計算的表示方式.
- 反碼:反碼的表示方法是:正數的反碼是其自己,負數的反碼是在其原碼的基礎上, 符號位不變,其他各個位取反。
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
可見若是一個反碼錶示的是負數, 人腦沒法直觀的看出來它的數值. 一般要將其轉換成原碼再計算.
- 補碼:正數的補碼就是其自己.負數的補碼是在其原碼的基礎上, 符號位不變, 其他各位取反, 最後+1. (即在反碼的基礎上+1)
Java中byte類型爲何是-128~127
對於正數[+1] = [00000001]原 = [00000001]反 = [00000001]補
對於負數[-1] = [10000001]原 = [11111110]反 = [11111111]補
- 因而可知,原碼、反碼和補碼徹底不一樣,既然反碼和補碼都難以被人們接受,那爲何還要有呢?
- 爲了讓計算機的運算更加方便,人們便設計出讓它只作加法,不作減法,而且符號位也參與加法。
如: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.
- 因而補碼的出現, 解決了0的符號以及兩個編碼的問題
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 =[0000 0001]反 + [1111 1110]反= [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]補 就是-128. 可是注意由於其實是使用之前的-0的補碼來表示-128, 因此-128並無原碼和反碼錶示.(對-128的補碼錶示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的),使用補碼, 不單單修復了0的符號以及存在兩個編碼的問題, 並且還可以多表示一個最低數. 這就是爲何8位二進制, 使用原碼或反碼錶示的範圍爲[-127, +127], 而使用補碼錶示的範圍爲[-128, 127]。
- 由於機器使用補碼, 因此對於編程中經常使用到的32位int類型, 能夠表示範圍是: [-231, 231-1] 由於第一位表示的是符號位.而使用補碼錶示時又能夠多保存一個最小值。其餘類型多出一位數,也都是同樣的原理。