1. 程式人生 > >原碼、反碼、補碼的理解與思考

原碼、反碼、補碼的理解與思考

原碼 反碼 補碼

原碼、反碼、補碼都是二進制表示數的方式

原碼
原碼:首位為符號位,0表示整數,1表示負數,其余位表示數值,例如0011表示+3,而1011表示-3。
優點:符合人類閱讀習慣,無論正數負數都能馬上讀出來
缺點:計算機做運算的時候不會把符號位提取出來,然後單獨計算數值位的,而是把整個數包括符號位一起參與運算,於是就導致了
問題一:0011+1011=1110(-6)的錯誤計算結果。
問題二:0存在著兩種表示方式。正零和負零的問題0000(+0)、1000(-0)

思考:如果世界上只有加法,沒有減法;只有正數,沒有負數。那麽計算機直接使用原碼也就沒這些問題了。只是,我們的世界也許會枯萎,也許會幹涸,但絕不會讓你省心。

為什麽會有原碼,反碼,補碼?

(有人說這是緣木求魚,好像還真是)
眾所周知,計算機采用二進制表示數。那麽具體如何表示其中也是有學問的。原碼是人類最直觀想到的表現方式,但原碼有缺點,於是產生了反碼,也有缺點,最後產生了補碼,相對完美,於是計算機系統大多使用補碼來存儲二進制數。反碼的作用主要是方便原碼到補碼的過渡,方便理解。
前面說過,如果只有加法和正數,那麽使用原碼沒有什麽問題。之所以出現反碼、補碼,正是為了解決負數和減法所帶來的問題。所以正數的原碼、反碼、補碼都是一樣的。

反碼
反碼:對原碼進行“符號位不變,數值位取反”
例如:-3原碼表示1011,反碼就是1100;+3和-3的和就是0011+1100=1111,而1111正是0(原碼1000的補碼就是1111)。於是解決了問題一。

優點:滿足絕對值相同的正負數相加值為零。可以把減法轉換成加法
缺點:依然還有兩種0的表示方式:0000(+0)和1111(-0)。
備註:反碼只是求補碼的過渡,不要糾結,為什麽要給它一個名字,明明沒什麽用啊。

思考:反碼解決了問題一,但還有問題二呢?於是出現了補碼。

問題:為什麽需要把減法轉換成加法運算?
因為計算機電路設計發展中,為了簡化電路設計,只保留了加法器,去除了減法器,將減法運算轉換成對負數的加法運算以達成運算目的。

補碼
補碼:對原碼進行“符號位不變,數值位取反”,再加一得到(對反碼+1得到)
例如:-3的反碼是1100,其補碼就是1101。
反碼中的0有兩種表示方式:0000(+0)和1111(-0),把1111+1並舍棄高位溢出得到0000,這和0000(+0)的表示方式是一樣的。

優點:解決了問題二,此時0只剩一種表示方式0000。同反碼一樣可以把減法轉換成加法。
缺點:對人不易讀。也算不上缺點,畢竟是給計算機讀的。

問題:為什麽負數總比正數多一個?
對於4位的原碼,表示範圍是:
[0111,1111],也就是[7,6,5,4,3,2,1,+0,-0,-1,-2,-3,-4,-5,-6,-7],2^4個,2^3-1個正數,兩個0,和2^3-1個負數。

對於4位的反碼,盡管負數的表示不同,但範圍和原碼是一致的
[7,6,5,4,3,2,1,+0,-0,-1,-2,-3,-4,-5,-6,-7]。

對於4位的補碼,表示範圍是:
[7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8],2^4個,2^3-1個正數,一個0,2^3個負數。
這是由於補碼的規則決定的,因為沒有反碼通過+1可以得到補碼1000。所以就人為規定了1000就是-8。這就是為什麽負數比正數多一個的原因。

例子:
Integer.MAX_VALUE 2147483647
原碼:0111 1111 1111 1111 1111 1111 1111 1111
反碼:0111 1111 1111 1111 1111 1111 1111 1111
補碼:0111 1111 1111 1111 1111 1111 1111 1111

Integer.MAX_VALUE的相反數 -2147483647
原碼:1111 1111 1111 1111 1111 1111 1111 1111
反碼:1000 0000 0000 0000 0000 0000 0000 0000
補碼:1000 0000 0000 0000 0000 0000 0000 0001

Integer.MIN_VALUE -2147483648
int類型的最小值比較特殊,因為絕對值2147483648原碼32位的int無法表示會高位溢出。
原碼:沒有
反碼:沒有
補碼:1000 0000 0000 0000 0000 0000 0000 0000(人為規定)

思考:為什麽最小的負數補碼不能通過原碼轉反碼再轉補碼的方法推算出來?
計算機教材裏面都是這樣的呀!其實從“取反”這樣的運算來看,不符合人類思維常用的推導過程,這其實更像是計算機處理器運算的過程。因為“取反”在計算機中是相對高效的運算。
實際上數學的推導過程是先根據數值位數求“模”,然後求負數相對於該“模”的最小正同余數,就是負數的補碼了。具體推導過程網絡搜。之所以變了樣,應該就是算法計算機化導致的,類似於乘法的計算機實現通常是左移位運算,除法通常是右移位運算。而計算機教材展示的是計算機實現該算法的原理,而不是數學推導原理。(網上找的,但我信了)

思考:如果確實如此,那我前面的思考過程不就成了扯淡了麽?
上述過程可能不是原始的數學推導過程,但確實是計算機的處理流程。是具體的實現方法,何來扯淡一說!但我的思考:“先有原碼,解決問題一得到反碼,解決問題二得到補碼”的邏輯就顯得扯淡了。畢竟目的就是得到補碼,根本不存在這演化過程,那麽反碼就更沒存在意義了。

原碼、反碼、補碼的理解與思考