在計算機內部,所有資訊都是用二進位制數串的形式表示的。整數通常都有正負之分,計算機中的整數分為無符號的和帶符號的。無符號的整數用來表示0和正整數,帶符號的證書可以表示所有的整數。由於計算機中符號和數字一樣,都必須用二進位制數串來表示,因此,正負號也必須用0、1來表示。通常我們用最高的有效位來表示數的符號(當用8位來表示乙個整數時,第8位即為最高有效位,當用16位來表示乙個整數時,第16位即為最高有效位。)0表示正號、1表示負號,這種正負號數位化的機內表示形式就稱為「機器數」,而相應的機器外部用正負號表示的數稱為「真值」。將乙個真值表示成二進位制字串的機器數的過程就稱為編碼。
無符號數沒有原碼、反碼和補碼一說。只有帶符號數才存在不同的編碼方式。
帶符號整數有原碼、反碼、補碼等幾種編碼方式。原碼即直接將真值轉換為其相應的二進位制形式,而反碼和補碼是對原碼進行某種轉換編碼方式。正整數的原碼、反碼和補碼都一樣,負數的反碼是對原碼的除符號位外的其他位進行取反後的結果(取反即如果該位為0則變為1,而該位為1則變為0的操作)。而補碼是先求原碼的反碼,然後在反碼的末尾位加1 後得到的結果,即補碼是反碼+1。ibm-pc中帶符號整數都採用補碼形式表示。(注意,只是帶符號的整數採用補碼儲存表示的,浮點數另有其儲存方式。)
採用補碼的原因或好處如下,採用補碼運算具有如下兩個特徵:
1)因為使用補碼可以將符號位和其他位統一處理,同時,減法也可以按加法來處理,即如果是補碼表示的數,不管是加減法都直接用加法運算即可實現。
2)兩個用補碼表示的數相加時,如果最高位(符號位)有進製,則進製被捨棄。
這樣的運算有兩個好處:
1)使符號位能與有效值部分一起參加運算,從而簡化運算規則。從而可以簡化運算器的結構,提高運算速度;(減法運算可以用加法運算表示出來。)
2)加法運算比減法運算更易於實現。使減法運算轉換為加法運算,進一步簡化計算機中運算器的線路設計。
下面深入分析上面所陳述的採用補碼的原因(目的)。
用帶符號位的原碼進行乘除運算時結果正確,而在加減運算的時候就出現了問題,如下: 假設字長為8bits
( 1 ) 10- ( 1 )10 = ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 顯然不正確.。
因為在兩個整數的加法運算中是沒有問題的,於是就發現問題出現在帶符號位的負數身上,對除符號位外的其餘各位逐位取反就產生了反碼。反碼的取值空間和原碼相同且一一對應。下面是反碼的減法運算:
( 1 )10 - ( 1 ) 10= ( 1 ) 10+ ( -1 ) 10= ( 0 )10
(00000001) 反+ (11111110)反 = (11111111)反 = ( -0 ) 有問題。
( 1 )10 - ( 2)10 = ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正確
問題出現在(+0)和(-0)上,在人們的計算概念中零是沒有正負之分的。
於是就引入了補碼概念。負數的補碼就是對反碼加一,而正數不變,正數的原碼反碼補碼是一樣的。在補碼中用(-128)代替了(-0),所以補碼的表示範圍為:
(-128~0~127)共256個。
注意:(-128)沒有相對應的原碼和反碼, (-128) = (10000000) 補碼的加減運算如下:
( 1 ) 10- ( 1 ) 10= ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)補 + (11111111)補 = (00000000)補 = ( 0 ) 正確
( 1 ) 10- ( 2) 10= ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 補+ (11111110) 補= (11111111)補 = ( -1 ) 正確
採用補碼表示還有另外乙個原因,那就是為了防止0的機器數有兩個編碼。原碼和反碼表示的0有兩種形式+0和-0,而我們知道,+0和-0是相同的。這樣,8位的原碼和反碼表示的整數的範圍就是-127~+127(11111111~01111111),而採用補碼表示的時候,00000000是+0,即0;10000000不再是-0,而是-128,這樣,補碼表示的數的範圍就是-128~+127了,不但增加了乙個數得表示範圍,而且還保證了0編碼的唯一性。
先寫出該負數的相反數(正數),再將該正數的二進位制形式寫出來,然後對這個二進位制位串按位取反,即若是1則改為0,若是0則改為1,最後在末位加1。
接下來的問題是,如何能將減法運算轉換成加法運算呢?
我們已經知道,原碼表示簡單直觀,與真值轉換容易。但如果用原碼表示,其符號位不能參加運算。在計算機中用原碼實現算術運算時,要取絕對值參加運算,符號位單獨處理,這對乘除運算是很容易實現的,但對加減運算是非常不方便的,如兩個異號數相加,實際是要做減法,而兩個異號數相減,實際是要做加法。在做減法時,還要判斷運算元絕對值的大小,這些都會使運算器的設計變得很複雜。而補碼這種編碼方式實際上正是針對上述問題的。通過用補碼進行表示,就可以把減法運算化為加法運算。
在日常生活中,有許多化減為加的例子。例如,時鐘是逢12進製,12點也可看作0點。當將時針從10點調整到5點時有以下兩種方法:
一種方法是時針逆時針方向撥5格,相當於做減法:
10-5=5
另一種方法是時針順時針方向撥7格,相當於做加法:
10+7=12+5=5 (mod 12)
這是由於時鐘以12 為模,在這個前提下,當和超過12時,可將12捨去。於是,減5相當於加7。同理,減4可表示成加8,減3可表示成加9,…。
在數學中,用「同餘」概念描述上述關係,即兩整數a、b用同乙個正整數m (m稱為模)去除而餘數相等,則稱a、b對m同餘,記作:
a=b (mod m)
具有同餘關係的兩個數為互補關係,其中乙個稱為另乙個的補碼。當m=12時,-5和+7,-4和+8,-3和+9就是同餘的,它們互為補碼。
從同餘的概念和上述時鐘的例子,不難得出結論:對於某一確定的模,用某數減去小於模的另乙個數,總可以用加上「模減去該數絕對值的差」來代替。因此,在有模運算中,減法就可以化作加法來做。
可以看出,補碼的加法運算所依據的基本關係為:
[x]補+ [y]補= [x+y]補
補碼減法所依據的基本關係式:
[x-y]補 =[x+(-y)]補= [x]補+ [-y]補
補充:一、八位表示的範圍:【有符號整數只能由其補碼表示】
-128 --- -1 或10000000 - 11111111
0 ---- 127 或00000000 - 01111111
注意:0的機器碼只有唯一的一種表示(編碼),即00000000;沒有-0這種說法,10000000不是-1的編碼,而是-128的編碼 ;另外10000000沒有補碼和反碼。
二、編碼
有真值(一般為十進位制有符號整數)到機器碼的轉換過程稱為編碼。
三、計算機採用補碼表示的原因
1)使符號位能與有效值部分一起參加運算,從而簡化運算規則。從而可以簡化運算器的結構,提高運算速度;(減法運算可以用加法運算表示出來。)
2)加法運算比減法運算更易於實現。使減法運算轉換為加法運算,進一步簡化計算機中運算器的線路設計。【從補碼運算的特徵理解!】
3)為了防止0的機器數有兩個編碼。
【例】求-10的補碼的方法如下:
1)取-10的絕對值10;
2)10的絕對值的二進位制形式為1010;
3)對1010取反得1111 1111 1111 0101(這裡假定乙個整數佔16位)
4)再加1得1111 1111 1111 0110;
即取補碼的步驟是將其絕對值按位取反再加1即可……
仍基於上例進行分析,16位儲存空間能夠儲存的有符號型數的範圍為-2^16~2^16-1,-10的補碼按無符號型別計算其值為65526。
程式設計時可用如下語句實現:
int i=-10;
i=~abs(i)+1;//abs為取絕對值,~為按位取反
這個語句涉及到了三個操作:一是求絕對值,二是按位取反,三是加1
其實可以用乙個加法操作即可搞定……
int i=-10;
i=i+2^16;
可以驗證,這種方法是等價的,-10+2^16=65526,在乙個有符號型儲存變數中儲存這個數,相當於儲存了乙個負數……
其通用的方法是:
變數a用n位來儲存,當其為負數時計算其補碼的方法是a=a+2^n;
如何計算乙個有符號數的補碼表示?
按照 譚浩強.c程式設計 第三版 北京 清華大學出版社,2005 的第40頁至第41頁所述,求乙個負數的補碼的方法如下 例 求 10的補碼的方法如下 1 取 10的絕對值10 2 10的絕對值的二進位制形式為1010 3 對1010取反得1111 1111 1111 0101 這裡假定乙個整數佔16...
關於補碼 無符號及有符號型別的理解
對於數值儲存有補碼 原碼 反碼三種方式 補碼 解決負數加法運算正負零問題,彌補了反碼的不足。原碼 可直觀反映出資料的大小。反碼 解決負數加法運算問題,將減法運算轉換為加法運算,從而簡化運算規則 負值採用反碼的形式進行儲存,計算機通過第一位來判斷乙個數值是否為負數,當第一位為1時,則為負數,否之則為正...
有符號數的原碼 反碼 補碼詳解
有符號數 signed d 符號位 數值位 例如 int i 7 int 型別佔4個位元組,1個位元組佔8個位,int佔32個位元位 7 根據8421碼得到二進位制原碼 0b00000000000000000000000000000111 int 型別的表數範圍 計算機中儲存有符號數的時候是按照補碼...