負數在計算機中如何表示?
舉例來說,+8在計算機中表示為二進制的1000,那麼-8怎麼表示呢?
很容易想到,可以将一個二進制位(bit)專門規定為符号位,它等于0時就表示正數,等于1時就表示負數。比如,在8位機中,規定每個位元組的最高位為符号位。那麼,+8就是00001000,而-8則是10001000。
但是,随便找一本《計算機原理》,都會告訴你,實際上,計算機内部采用2的補碼(Two's Complement)表示負數。
什麼是2的補碼?
它是一種數值的轉換方法,要分二步完成:
第一步,每一個二進制位都取相反值,0變成1,1變成0。比如,00001000的相反值就是11110111。
第二步,将上一步得到的值加1。11110111就變成11111000。
是以,00001000的2的補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。
不知道你怎麼看,反正我覺得很奇怪,為什麼要采用這麼麻煩的方式表示負數,更直覺的方式難道不好嗎?
昨天,我在一本書裡又看到了這個問題,然後就花了一點時間到網上找資料,現在總算徹底搞明白了。
2的補碼的好處
首先,要明确一點。計算機内部用什麼方式表示負數,其實是無所謂的。隻要能夠保持一一對應的關系,就可以用任意方式表示負數。是以,既然可以任意選擇,那麼理應選擇一種最友善的方式。
2的補碼就是最友善的方式。它的便利展現在,所有的加法運算可以使用同一種電路完成。
還是以-8作為例子。
假定有兩種表示方法。一種是直覺表示法,即10001000;另一種是2的補碼表示法,即11111000。請問哪一種表示法在加法運算中更友善?
随便寫一個計算式,16 + (-8) = ?
16的二進制表示是 00010000,是以用直覺表示法,加法就要寫成:
00010000
+10001000
---------
10011000
可以看到,如果按照正常的加法規則,就會得到10011000的結果,轉成十進制就是-24。顯然,這是錯誤的答案。也就是說,在這種情況下,正常的加法規則不适用于正數與負數的加法,是以必須制定兩套運算規則,一套用于正數加正數,還有一套用于正數加負數。從電路上說,就是必須為加法運算做兩種電路。
現在,再來看2的補碼表示法。
00010000
+11111000
---------
100001000
可以看到,按照正常的加法規則,得到的結果是100001000。注意,這是一個9位的二進制數。我們已經假定這是一台8位機,是以最高的第9位是一個溢出位,會被自動舍去。是以,結果就變成了00001000,轉成十進制正好是8,也就是16 + (-8) 的正确答案。這說明了,2的補碼表示法可以将加法運算規則,擴充到整個整數集,進而用一套電路就可以實作全部整數的加法。
2的補碼的本質
在回答2的補碼為什麼能正确實作加法運算之前,我們先看看它的本質,也就是那兩個步驟的轉換方法是怎麼來的。
要将正數轉成對應的負數,其實隻要用0減去這個數就可以了。比如,-8其實就是0-8。
已知8的二進制是00001000,-8就可以用下面的式子求出:
00000000
-00001000
---------
因為00000000(被減數)小于0000100(減數),是以不夠減。請回憶一下國小算術,如果被減數的某一位小于減數,我們怎麼辦?很簡單,問上一位借1就可以了。
是以,0000000也問上一位借了1,也就是說,被減數其實是100000000,算式也就改寫成:
100000000
-00001000
---------
11111000
進一步觀察,可以發現100000000 = 11111111 + 1,是以上面的式子可以拆成兩個:
11111111
-00001000
---------
11110111
+00000001
---------
11111000
2的補碼的兩個轉換步驟就是這麼來的。
為什麼正數加法适用于2的補碼?
實際上,我們要證明的是,X-Y或X+(-Y)可以用X加上Y的2的補碼完成。
Y的2的補碼等于(11111111-Y)+1。是以,X加上Y的2的補碼,就等于:
X + (11111111-Y) + 1
我們假定這個算式的結果等于Z,即 Z = X + (11111111-Y) + 1
接下來,分成兩種情況讨論。
第一種情況,如果X小于Y,那麼Z是一個負數。這時,我們就對Z采用2的補碼的逆運算,求出它對應的正數絕對值,再在前面加上負号就行了。是以,
Z = -[11111111-(Z-1)] = -[11111111-(X + (11111111-Y) + 1-1)] = X - Y
第二種情況,如果X大于Y,這意味着Z肯定大于11111111,但是我們規定了這是8位機,最高的第9位是溢出位,必須被舍去,這相當于減去100000000。是以,
Z = Z - 100000000 = X + (11111111-Y) + 1 - 100000000 = X - Y
這就證明了,在正常的加法規則下,可以利用2的補碼得到正數與負數相加的正确結果。換言之,計算機隻要部署加法電路和補碼電路,就可以完成所有整數的加法。
轉自
另記載下反碼的規律
~ (反碼): 01001 ~ 後 10110,即1變0 , 0變1
6反碼結果是-7, 整數a的反碼結果= -a -1
(~6) = -7
-6 = -7 + 1;
(~8) = -9:-8 = -9 + 1;
(~16) = -17:-16 = -17 + 1;
~(-6)= -(-6)-1=5 ;
(~a)先把a變為-a,-a - 1 = (~a);