1. 程式人生 > >負數為什麼要用補碼來表示?

負數為什麼要用補碼來表示?

上篇文章講了“負數在計算機中是怎麼儲存的”。看完之後,應該對原碼,反碼,補碼有了基本的瞭解了。

今天,我們深入探討一下,為什麼計算機中要用補碼來表示負數?

首先,我們應該清楚,原碼是方便給人看的。看到一個數的原碼,我們就能根據符號位和後邊的二進位制位,計算出這個數的實際值。為了簡單起見,我以一個位元組8位來舉例,如

// 1 的原碼 ,最高位0代表正數
0000 0001
// -1 的原碼, 最高位1代表負數
1000 0001

可以看到,1和 -1 的原碼只有符號位不同。然後,思考一個問題,1 - 1 = ?

是的,我們可以直接通過減法去計算,得出1-1=0 。但是,做減法運算時,可能會遇到不夠減而需要借位的情況,這顯然是比較麻煩的。我們換一種思路。 1-1 在數學中等同於 1+(-1)。這樣,把減法轉換為加法就簡單的多了,只需要考慮進位就可以了。(其實,計算機中只有加法器,沒有減法器,因此減法是通過加法器來計算的。)

於是,我們看下,把1和-1的原碼相加等於多少(需要讓符號位也參與運算)

  0000 0001
+ 1000 0001
  1000 0010

結果是 -2 ,這顯然不符合我們的預期。

為了解決原碼減法的問題,於是,出現了反碼。使用反碼,再來計算一下。

// 1的反碼,同原碼
0000 0001
// -1的反碼,符號位不變,其他取反
1111 1110

相加之後,得 1111 1111 ,這是反碼,轉為原碼為 1000 0000 ,即為 -0 。

但是,這又有問題了,在數學中0就是0,怎麼到這還有 -0,+0之分。按照原碼的概念來算,+0的原碼為0000 0000 , -0 的原碼為 1000 0000 。問題就出在這了,如果遇到0的計算,是應該用 +0 還是用 -0 計算呢,這就會產生分歧。於是,補碼出現了,解決了0的符號問題 。

// 1的補碼,同原碼
0000 0001
// -1的補碼,反碼 +1
1111 1111

相加得 1 0000 0000 ,最高位進位之後,超過了8位,於是捨去,即為0000 0000。此為補碼,轉為原碼也是0000 0000 ,這不就是0 嗎。

這樣一來,用補碼0000 0000來表示0,就解決了+0和-0在原碼上的分歧,統一了0的二進位制表示方法。

那,又有疑問了,-0跑哪去了呢? 其實,-0即1000 0000在這用來表示 -128。但是,注意表示的是 -128的補碼,因此 -128沒有原碼和反碼。

那為什麼用 1000 0000表示 -128呢 ?

先看下 -127 的原碼、反碼和補碼:
原碼: 1111 1111
反碼: 1000 0000
補碼: 1000 0001

我們知道數學中 -127 -1 = -128 ,所以 -127的補碼 -1 也應該等於 -128的補碼,即
1000 0001 -1 = 1000 0000。因此1000 0000就是 -128的補碼。

在一個位元組8位中,如果用原碼來表示值的大小範圍,只能是 1111 1111 ~ 0111 1111,即-127~127 。但是,如果用補碼就可以表示 -128~127,正好是2^8,256個數。

因此,-0可以表示一個最低數。在8位二進位制中它是1000 0000 ,在32位中,它就是 1000 0000 0000 0000 0000 0000 0000 0000 ,int的最小值。(32位數值大小範圍為 -2^31 ~ 2^31 -1)

總結:補碼的存在解決了0的符號問題,同時統一了計算機的加減法運算。