1.3.2 有符號二進制數的算術運算
1.原碼、反碼和補碼
數字系統只能識別和處理用0和1表示的二進制形式的數碼。有符號二進制數包含符號和數值信息,符號位一般放在最高位,用0和1分別表示這個數是正數還是負數,數值位則表示該數的大小。用“+”“-”符號表示出來的數稱為真值。將數的“+”“-”符號和數值數碼化后的二進制數稱為機器數。機器數表示形式有三種:原碼、反碼和補碼。
計算機中實際用8位二進制代碼表示一個字符,稱為一個字節。若計算機的寄存器為8位(一個字節),則數的存儲格式如圖1-6所示。最高位(MSB)為符號位,若此符號位為0,則該數為正(+);若符號位為1,則該數為負(-)。剩下的7位表示該數的絕對值大小。這種自然表示機器數的形式稱為原碼。原碼表示簡單、直觀,但用原碼進行減法運算時,首先需要比較兩個數絕對值的大小,然后用絕對值大的數減去絕對值小的數求出差值,并以絕對值大的數的符號作為差值的符號。這個操作過程比較麻煩,還需使用數值比較電路和減法運算電路,不容易實現。計算機等數字系統均采用補碼進行有符號二進制數的減法運算。為了計算減法方便,因此引入了反碼和補碼。

圖1-6 有符號二進制數在8位寄存器中的存儲格式
正數的原碼、反碼和補碼完全相同。
負數的原碼、反碼和補碼符號位都為1,反碼的數值位是原碼的逐位求反(即1變0,0變1),反碼也因此而得名。補碼數值位為其反碼加1得到,或簡稱“逐位求反加1”。
例如:[+6]原碼=[+6]反碼=[+6]補碼=0 0110
[-6]原碼=1 0110[-6]反碼=1 1001[-6]補碼=1 1010
特殊:[+0]原碼=[+0]反碼=[+0]補碼=0 0000000
[-0]原碼=1 0000000[-0]反碼=1 1111111
[-0]補碼=1 1111111+1=0 0000000
所以有:[+0]補碼=[-0]補碼=0 0000000
【例1-7】求二進制數x=+1011,y=-1011在八位存儲器中的原碼、反碼和補碼的表示形式。
解:無論是原碼、反碼和補碼形式,八位存儲器的最高位為符號位,其他位則是數值部分的編碼表示。在數值部分中,對于正數,原碼、反碼和補碼按位相同,而對于負數,反碼是原碼的逐位求反,補碼則是原碼的逐位求反加1。所以,二進制數x和y的原碼、反碼和補碼分別表示如下:
[x]原碼=0 0001011,[x]反碼=0 0001011,[x]補碼=0 0001011
[y]原碼=1 0001011,[y]反碼=1 1110100,[y]補碼=1 1110101
表1-4列出了帶符號的3位二進制數原碼、反碼、補碼對應關系。
對于n位有符號的二進制數的原碼、反碼及補碼所表示的二進制數的范圍分別為
1)原碼:-(2n-1-1)~+(2n-1-1)。
2)反碼:-(2n-1-1)~+(2n-1-1)。
3)補碼:-2n-1~+(2n-1-1)。
表1-4 3位二進制數的原碼、反碼、補碼對照

2.補碼運算
補碼的原理可以用時鐘調整來說明。如圖1-7所示,如果要將時鐘從9點撥到4點,可以向后撥5個格,9-5=4,也可以向前撥7個格,9+7=16。由于時鐘是一個十二進制的計數體制,一個計數系統的計數基數稱為“模”,超過模12以后的“進位”將自動消失,舍去進位(溢出)后,剩下的余數即為需要的結果,即16-12=4,也將表針撥回到了4點。這個例子說明,9-5的減法運算可以用9+7的加法運算代替。所以稱7為-5對模12的補數,也稱為補碼(Complement)。

圖1-7 說明補碼運算原理的例子
在數字系統中,有符號二進制數一律用補碼進行存儲和計算。通過引入補碼,減法運算可以變為加法運算(減去一個正數相當于加上一個負數)。補碼加、減運算規則如下:
[X+Y]補=[X]補+[Y]補
[X-Y]補=[X+(-Y)]補=[X]補+[-Y]補
{[X±Y]補}補=[X±Y]原
【例1-8】試用4位二進制補碼計算6-2。
解:因為(6-2)補=(6)補+(-2)補
=0110+1110
=0100

由計算過程可得:6-2=4。
進行二進制補碼運算時,被加數和加數的補碼的位數要相同,因此兩個二進制數的補碼采用相同的位數表示,即讓兩個二進制數的補碼的符號位對齊。兩個二進制數的補碼相加時,方括號中的1是進位,在計算時自動舍去,因為上述運算是以4位二進制補碼表示的,計算結果仍然保留4位。
【例1-9】試用4位二進制補碼計算7+4。
解:因為(7+4)補=(7)補+(4)補
=0111+0100

=1011
計算結果補碼1011表示-5,而實際正確的結果應該為11。錯誤產生的原因在于4位二進制補碼中,有3位是數值位,它所表示的范圍為-8~+7,而本題的結果需要4位數值位表示,因而產生溢出。
解決溢出的方法:進行位擴展,即用5位以上的二進制數補碼表示,就不會產生溢出了。
即(7+4)補=(7)補+(4)補
=00111+00100
=01011
計算結果01011表示+11,而實際正確的結果也是11。
3.溢出的判別
溢出的判別對有符號數的運算是非常重要的,它表明結果是否超出范圍。“溢出”僅發生在兩個同符號的數(兩個正數或者兩個負數)相加的情況下。如果兩個正數相加的結果大于機器數所能表示的最大正數,稱為正溢出;如果兩個負數相加的結果小于機器數所能表示的最小負數,稱為負溢出。
溢出判別的簡便規則如下:
1)符號判斷法:同符號數相加可能溢出,異符號數相加不會溢出。
2)進位判斷法:若進位位和數的符號位取值相同,則運算沒有產生溢出,否則發生溢出。
通過圖1-8所示的實例來說明兩個同符號的數溢出判別問題。

圖1-8 溢出的判別
對于兩個符號相同的數做加法運算,若進位位和數的符號位取值相同,則運算沒有產生溢出,結果是正確的,如圖1-8a、b所示;若進位位和數的符號位取值相反,則其運算產生了溢出,結果是錯誤的,如圖1-8c、d所示。錯誤產生的原因在于4位二進制補碼中有3位是數值位,所表示的范圍為-8~+7。而圖1-8c、d的計算結果分別為+9(1001為-7的補碼)和-9(0111為+7的補碼),均超過了該表示范圍,因而產生了溢出。當產生溢出時,可通過擴展二進制數的位數來保證計算結果的正確性。
思考與練習
1.3-1 為什么說二進制數的加法運算是算術運算的基礎?
1.3-2 二進制數的減法運算過程有什么規律?
1.3-3 說明反碼與補碼之間的關系。
1.3-4 說明溢出產生的原因。