二補數
二補數(英語:)是一種用二進位表示有符号數的方法,也是一種將數字的正負號變號的方式,常在電腦科學中使用。二補數以有符號位元的二進位數定義。
「二補數」的各地常用名稱 | |
---|---|
中国大陸 | |
臺灣 | |
港澳 |
符號 | |||||||||
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | = | 127 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | = | 2 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | = | 1 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | = | 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | = | −1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | = | −2 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | = | −127 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | = | −128 |
正數和0的二補數就是該數字本身再補上最高位元0。負數的二補數則是將其绝对值按位取反再加1。
二補數系統的最大優點是可以在加法或減法處理中,不需因為數字的正負而使用不同的計算方式。只要一種加法電路就可以處理各種有號數加法,而且減法可以用一個數加上另一個數的二補數來表示,因此只要有加法電路及二補數電路即可完成各種有號數加法及減法,在電路設計上相當方便。
另外,二補數系統的0就只有一個表示方式,這和一補數系統不同(在一補數系統中,0有二種表示方式),因此在判斷數字是否為0時,只要比較一次即可。
右側的表是一些8-bit二補數系統的整數。它的可表示的範圍包括-128到127,總共256(=28)個整數。
數字表示方式
說明
二補數 | 十進位 |
---|---|
0111 | 7 |
0110 | 6 |
... | ... |
0010 | 2 |
0001 | 1 |
0000 | 0 |
1111 | −1 |
1110 | −2 |
... | ... |
1001 | −7 |
1000 | −8 |
以下用4位元的二補數數字來說明二補數系統的數字表示方式。
- 在表示正數和零時,二補數數字和一般二進位一樣,唯一的不同是在二補數系統中,正數的最高位元恆為0,因此4位元的二補數正數,最大數字為0111 (7)。
- 二補數數字的負數,最高位元恆為1,4位元二補數的數字中,最接近0的負數為1111 (-1),以此類推,因此絕對值最大的負數是1000 (-8)。
以上的表示方式在電腦處理時格外方便,用以下的例子說明:
0011 (3) + 1111 (-1) -------------- 10010 (2)
結果10010似乎是錯的,因為已經超過四個位元,不過若忽略掉(從右開始數)第5個位元,結果是0010 (2),和我們計算的結果一樣。而且若可以將二進位的1111 (-1)變號為0001 (1),以上的式子也可以計算減法:3-1 = 2。
在n位元的二補數加減法中,忽略第n+1個位元的作法在各種有號數加法下都適用(不過在判斷是否溢位(overflow)時,仍然會用到第n+1個位元)。因此在二補數的系統,加法電路就可以處理有負數的加法,不需另外處理減法的電路。而且,只要有電路負責數字的變號(例如將1變換為 -1),也可以用加法電路來處理減法。而數字的變號就用計算數字的二補數來完成。
在一般n位元的二進位數字中,最高有效位元(MSB)第 n位元代表的數字為 2n−1。不過,在n位元的二補數系統中,最高有效位元(MSB)第 n位元表示符號位元,若符號位元為0,數字為正數或0,若符號位元為1,數字為負數。以下是n位元的二補數系統中,幾個特別的數字:
二補數 | 實際數字 | 附註 |
---|---|---|
0 111....111 | 2n−1-1 | 当前有符号位区分的最大正數 |
... | ... | |
0 000....001 | 1 | |
0 000....000 | 0 | |
1 111....111 | -1 | |
... | ... | |
1 000....001 | - 2n−1+1 | 当n<当前所在二補數系统内所含的最大位元数量(最大位元数量是4的整数倍,且整数倍数大于等于1),得出根据当前n的值从而解得有符号位区分的负整数(同时根据n的值也确定了最大位元数量的值)。 |
1 000....000 | - 2n−1 | 当n=当前所在二補數系统内所含的最大位元数量(最大位元数量是4的整数倍,且整数倍数大于等于1),得出根据当前n的值从而解得有符号位区分的最小负数(同时根据n的值也确定了最大位元数量的值)。 |
因此,在8位元的二補數系統中,可以表示的最大正數為28−1-1 = 127,可以表示最小的負數為 -28−1 = -128
計算二補數
在計算二進制數字的二補數時,會將數字進行位元反相運算,再將結果加1,不考慮溢位位元(一般情形,溢位位元會為0),就可以得到該數字的二補數。
以下考慮用有符號位8位元二進位表示的數字5:
- 0000 0101 (5)
其最高位元為0,因為此數字為正數。若要用二補數系統表示 -5,首先要將5的二進位進行反相運算〔1變為0,0變為1 〕:
- 1111 1010
目前的數字是數字5的一補數,因此需要再加1,才是二補數:
- 1111 1011 (-5)
以上就是在二補數系統中 -5的表示方式。其最高位元為1,因為此數字確實為負數。
一個負數的二補數就是其對應的正數。以 -5為例,先求數字的一補數:
- 0000 0100
再加一就是 -5的二補數,也就是5。
- 0000 0101 (5)
簡單來說,數字a(正負數皆可)的二補數即為 -a。
若要計算n位數二補數二進位對應的十進位,需要知道每位數對應的數字,除了最高位元外,其他位元的對應數字均和一般二進位相同,即第i位數表示數字2i−1。但最高位元若為1時,其表示數字為 -2n−1,因此若用此方式計算0000 0101表示的數字,其結果為:
- 1111 1011 (−5) = −128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = (−27 + 26 + ...) = −5
特別的數字
有两個數字的二補數等於本身:一個是0,另一個為該位元内可表示有符号位区分的二进制形式的最大負數(即1000...)。
0的二補數計算方式(以8位元為例)如下:先計算它的一補數:
- 1111 1111
再將一補數加一:
- 0000 0000,溢位位元二进制值 = 1(二进制)
忽略溢位,其結果為0(0是唯一計算二補數過程中會出現溢位的數字。)。因此0的二補數為0。而0 x (-1) = 0,因此其二補數仍滿足「數字a的二補數為 -a」的原則。
若計算1000 0000(这是8位元内可表示有符号位区分的二进制形式的最大负数-128)的二補數:先計算它的一補數:
- 0111 1111
再加一就是它的二補數。
- 1000 0000
1000 0000 (-128)的二補數仍為1000 0000 (-128)。但(-128) x (-1) = 128,因此其二補數是以上規則的例外。
总结:由于0可以等于0的二補數-0,以及同样因為8位元的二補數可显示的值範圍為 -128 ~ 127,但-128的二補數128無法用在已有位元数量为8的位元数量内的可用二補數表示。【在計算其他位數内的可表示有符号位区分的二进制形式的最大負數(即1000...000)時,也會有類似情形。】
所以:0和-128的确是「數字a的二補數為 -a」原则中两个特别的数字。
方法二
以另一種較簡單的方式,可以找出二進位數字的二補數:
- 先由最低位元開始找。
- 若該位元為0,將二補數對應位元填0,繼續找下一位元(較高的位元)。
- 若找到第一個為1的位元,將二補數對應位元填1。
- 將其余未轉換的位元進行位元反相,將結果填入對應的二補數。
以0011 1100為例(圖中的^表示目前轉換的數字,-表示還不確定的位數):
原數字 补码 0011 1100 ---- ---0(此位元為0) ^ 0011 1100 ---- --00(此位元為0) ^ 0011 1100 ---- -100(找到第1個為1的位元) ^ 0011 1100 1100 0100(其余位元直接反相) ^
因此其結果為1100 0100
符號延展
十進位 | 4位元二補數 | 8位元二補數 |
---|---|---|
5 | 0101 | 0000 0101 |
-3 | 1101 | 1111 1101 |
將一個特定位元二補數系統的數字要以較多位元表示時(例如,將一個位元組的變數複製到另一個二個位元組),所有增加的高位元都要填入原數字的符號位元。在一些微處理機中,有指令可以執行上述的動作。若是沒有,需要自行在程式中處理。==>
在二補數系統中,當數字要向右位移幾個位元時,在位移後需將符號位元再填入原位置(算术移位),保持符號位元不變。以下是二個例子:
數字 0010 1010 1010 1010 向右位移一次 0001 0101 1101 0101 向右位移二次 0000 1010 1110 1010
而當一個數字要向左位移n個位元時,最低位元填n个0,权值最高的n个位被抛弃。以下是二個例子:
數字 0010 1010 1010 1010 向左位移一次 0101 0100 0101 0100 向左位移二次 1010 1000 1010 1000
向右位移一次相當於除以2,利用算术移位的方式可以確保位移後的數字正負號和原數字相同,因為一數字除以2後,不會改變其正負號。 注意:向左位移一次相當於乘以2,虽然乘以在理论上并不会改变一个数的符号,但是在二補數系统中,用以表示数的二进制码长度有限,能够表示的数的范围也是有限的:若一个数的高权值上的数位已经被占用,此时再将这个数左移若干位(乘以2n)的话,有可能造成数位溢出(overflow),高权值上的数将会失去,对于绝对值很大数,这将造成整体表达的错误。
二補數的工作原理
为什么二補數能这么巧妙实现了正负数的加减运算?答案是:指定n位元字长,那么就只有2n个可能的值,加减法运算都存在上溢出与下溢出的情况,实际上都等价于模2n的加减法运算。这对于n位元无符号整数类型或是n位元有符号整数类型都同样适用。
例如,8位元无符号整数的值的范围是0到255.因此4+254将上溢出,结果是2,即。
例如,8位元有符号整数的值的范围,如果规定为−128到127,则126+125将上溢出,结果是−5,即。
对于8位元字长的有符号整数类型,以28即256为模,则
所以模256下的加减法,用0, 1, 2,…, 254,255表示其值,或者用−128, −127,…, −1, 0, 1, 2,…,127是完全等价的。−128与128,−127与129,…,−2与254,−1与255可以互换而加减法的结果不变。从而,把8位元(octet)的高半部分(即二进制的1000 0000到1111 1111)解释为−128到−1,同样也实现了模256的加减法,而且所需要的CPU加法运算器的电路实现与8位元无符号整数并无不同。
实际上对于8比特的存储单元,把它的取值[00000000,…, 11111111]解释为[0, 255],或者[-1, 254],或者[-2, 253],或者[-128, 127],或者[-200, 55],甚至或者[500, 755],对于加法硬件实现并无不同。
運算
加法
二補數系統數字的加法和一般加法相同,而且在運算完成後就可以看出結果的正負號,不需特別的處理。
正數與負數相加不會出現上溢錯誤,因为它们的和一定会小于加数。上溢错误只有在两个正数或两个负数相加时才可能发生,这时候最高有效位(正负号)會變成相反。
以15加-5為例:
11111 111(进位) 0000 1111 (15) + 1111 1011 (-5) ----------------- 0000 1010 (10)
由於加數和被加數都是8位元,因此運算結果也限制在8位元內。第8位元相加後產生的進位不考慮(因為不存在第9位元)的1被忽略,所以其結果為10。而15 + (-5) = 10,計算結果正確。
在以上計算式中,可以由進位列的最左側二個位元得知結果是否出現溢位。溢位就是數字的絕對值太大,以致於無法在指定的二進位位元個數來表示(在此例中,是超過8位元的範圍)。若進位列的最左側二個位元同為0或同為1,表示結果正確,若是一個為0,另一個為1,表示出現溢位錯誤。也可以對此二個位元進行异或運算,結果為1時,表示出現溢位錯誤。以下以7 + 3的4位元加法說明溢位錯誤的情形。
0111(进位) 0111 (7) + 0011 (3) ------------ 1010 (−6) 結果不正確!
在此例中,進位列的最左側二個位元為01,因此出現溢位錯誤。溢位的原因是7 + 3的結果(10)超過二補數系統4位元所可以表示的數字範圍 -8~7。
故为防止溢位錯誤,二補數在进行加法运算时通常将符号位进行复制后追加到最高位之前,即设二補數B的位数为WIDTH,则B′={B[WIDTH-1],B}。应注意此处B′的位数为WIDTH+1。 如上两例用此方法进行计算:
11 1111 111(进位) 0 0000 1111 (15) +1 1111 1011 (-5) ------------------- (1)0 0000 1010 (10)
由于WIDTH+1=8+1=9,故而第十位的1同样由于溢位而被省略,结果仍为10。两负数(符号位为1)相加时同理。
111(进位) 0 0111 (7) + 0 0011 (3) -------------- 0 1010 (10) 結果正確!
由于WIDTH+1=4+1=5,故第五位的0仍为符号位,得结果正数10(十进制)。
減法
减法通常转化为加法进行运算,将减数与被减数的补码进行加法运算,即可得出差。
乘法
乘法在電腦的世界裡其實就是不斷的做加法。
例如:3*5=3+3+3+3+3=15
除法
除法就是相減。
例如:10/3=10-3-3-3=1mod3 而減法又可做二補數相加,所以所有四則運算的基礎都是由加法而來。
參考資料
- M Morris Mano; Michael D Ciletti. . 培生教育. 2013: 第27頁. ISBN 9780273764526.