首頁 > theory > algorithm > > 正文

原碼, 反碼, 補碼-減法變加法-同余理論:詳解

發布人:[email protected]    點擊:

原碼, 反碼, 補碼-減法變加法-同余理論:詳解 ——或許這樣好理解點

一. 機器數和真值

在學習原碼, 反碼和補碼之前, 需要先了解機器數和真值的概念.

1、機器數

一個數在計算機中的二進制表示形式,  叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數為0, 負數為1.

比如,十進制中的數 +3 ,計算機字長為8位,轉換成二進制就是00000011。如果是 -3 ,就是 10000011 。

那么,這里的 00000011 和 10000011 就是機器數。

2、真值

因為第一位是符號位,所以機器數的形式值就不等于真正的數值。例如上面的有符號數 10000011,其最高位1代表負,其真正數值是 -3 而不是形式值131(10000011轉換成十進制等于131)。所以,為區別起見,將帶符號位的機器數對應的真正數值稱為機器數的真值。

例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = -000 0001 = -1 

二. 原碼, 反碼, 補碼的基礎概念和計算方法.

在探求為何機器要使用補碼之前, 讓我們先了解原碼, 反碼和補碼的概念.對于一個數, 計算機要使用一定的編碼方式進行存儲. 原碼, 反碼, 補碼是機器存儲一個具體數字的編碼方式.

1. 原碼

原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值. 比如如果是8位二進制:

[+1] = 0000 0001

[-1] = 1000 0001

第一位是符號位. 因為第一位是符號位, 所以8位二進制數的取值范圍就是:

[1111 1111 , 0111 1111]

[-127 , 127]

原碼是人腦最容易理解和計算的表示方式.

2. 反碼

反碼的表示方法是:

正數的反碼是其本身

負數的反碼是在其原碼的基礎上, 符號位不變,其余各個位取反.

[+1] = [00000001] = [00000001]

[-1] = [10000001] = [11111110]

可見如果一個反碼表示的是負數, 人腦無法直觀的看出來它的數值. 通常要將其轉換成原碼再計算.

3. 補碼

補碼的表示方法是:

正數的補碼就是其本身

負數的補碼是在其原碼的基礎上, 符號位不變, 其余各位取反, 最后+1. (即在反碼的基礎上+1)

[+1] = [00000001] = [00000001] = [00000001]

[-1] = [10000001] = [11111110] = [11111111]

對于負數, 補碼表示方式也是人腦無法直觀看出其數值的. 通常也需要轉換成原碼在計算其數值.

 

數值的補碼表示分兩種情況: 
(1)正數的補碼:與原碼相同。 
      例如,+9的原碼和補碼都是00001001。 
(2)負數的補碼:符號位為1,其余位為該數絕對值的原碼按位取反,然后整個數加1。 
例如,-7的補碼:因為是負數,則符號位為1,整個為10000111;其余7位為-7的絕對值+7的原碼 0000111按位取反為1111000;再加1,所以-7的補碼是11111001。 

 


已知一個數的補碼,求原碼的操作分兩種情況: 
(1)如果補碼的符號位為0;,表示是一個正數,所以補碼就是該數的原碼。 
(2)如果補碼的符號位為1,表示是一個負數,求原碼的操作
可以是:符號位不變,-1再取反

也可以:符號位不變,其余各位取反,然后再整個數加1。 

 

例如,已知一個補碼為1111 1001,則原碼是1000 0111(-7):因為符號位為1,表示是一個負數,所以該位不變,仍為 1;
減1, 
1111 1000取反,                    1000 0111
取反后為000 0110;再加1,所以是1000 0111。 

三. 為何要使用原碼, 反碼和補碼

在開始深入學習前, 我的學習建議是先"死記硬背"上面的原碼, 反碼和補碼的表示方式以及計算方法.

現在我們知道了計算機可以有三種編碼方式表示一個數. 對于正數因為三種編碼方式的結果都相同:

[+1] = [00000001] = [00000001] = [00000001]

所以不需要過多解釋. 但是對于負數:

[-1] = [10000001] = [11111110] = [11111111]

可見原碼, 反碼和補碼是完全不同的. 既然原碼才是被人腦直接識別并用于計算表示方式, 為何還會有反碼和補碼呢?


首先, 因為人腦可以知道第一位是符號位, 在計算的時候我們會根據符號位, 選擇對真值區域的加減. (真值的概念在本文最開頭). 但是對于計算機, 加減乘數已經是最基礎的運算, 要設計的盡量簡單. 計算機辨別"符號位"顯然會讓計算機的基礎電路設計變得十分復雜! 于是人們想出了將符號位也參與運算的方法. 我們知道, 根據運算法則減去一個正數等于加上一個負數, 即: 1-1 = 1 + (-1) = 0 , 所以機器可以只有加法而沒有減法, 這樣計算機運算的設計就更簡單了.


于是人們開始探索 將符號位參與運算, 并且只保留加法的方法. 首先來看原碼:

計算十進制的表達式: 1-1=0

1 - 1 = 1 + (-1) = [00000001] + [10000001] = [10000010] = -2

如果用原碼表示, 讓符號位也參與計算, 顯然對于減法來說, 結果是不正確的.這也就是為何計算機內部不使用原碼表示一個數.

為了解決原碼做減法的問題, 出現了反碼:

計算十進制的表達式: 1-1=0

1 - 1 = 1 + (-1) = [0000 0001] + [1000 0001]= [0000 0001] + [1111 1110] = [1111 1111] = [1000 0000] = -0

發現用反碼計算減法, 結果的真值部分是正確的. 而唯一的問題其實就出現在"0"這個特殊的數值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.


于是補碼的出現, 解決了0的符號以及兩個編碼的問題:

1-1 = 1 + (-1) = [0000 0001] + [1000 0001] = [0000 0001] + [1111 1111] = [0000 0000]=[0000 0000]

這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128:

(-1) + (-127) = [1000 0001] + [1111 1111] = [1111 1111] + [1000 0001] = [1000 0000]

-1-127的結果應該是-128, 在用補碼運算的結果中, [1000 0000]補 就是-128. 但是注意因為實際上是使用以前的-0的補碼來表示-128, 所以-128并沒有原碼和反碼表示.(對-128的補碼表示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的)


使用補碼, 不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示一個最低數. 這就是為什么8位二進制, 使用原碼或反碼表示的范圍為[-127, +127], 而使用補碼表示的范圍為[-128, 127].


因為機器使用補碼, 所以對于編程中常用到的32位int類型, 可以表示范圍是: [-231, 231-1] 因為第一位表示的是符號位.而使用補碼表示時又可以多保存一個最小值.

四 原碼, 反碼, 補碼 再深入

計算機巧妙地把符號位參與運算, 并且將減法變成了加法, 背后蘊含了怎樣的數學原理呢?

將鐘表想象成是一個1位的12進制數. 如果當前時間是6點, 我希望將時間設置成4點, 需要怎么做呢?我們可以:

1. 往回撥2個小時: 6 - 2 = 4

2. 往前撥10個小時: (6 + 10) mod 12 = 4

3. 往前撥10+12=22個小時: (6+22) mod 12 =4

2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余數是4.

所以鐘表往回撥(減法)的結果可以用往前撥(加法)替代!

現在的焦點就落在了如何用一個正數, 來替代一個負數. 上面的例子我們能感覺出來一些端倪, 發現一些規律. 但是數學是嚴謹的. 不能靠感覺.

首先介紹一個數學中相關的概念: 同余

同余的概念

兩個整數a,b,若它們除以整數m所得的余數相等,則稱a,b對于模m同余

記作 a b (mod m)

讀作 a 與 b 關于模 m 同余。

舉例說明:

4 mod 12 = 4

16 mod 12 = 4

28 mod 12 = 4

所以4, 16, 28關于模 12 同余.

負數取模

正數進行mod運算是很簡單的. 但是負數呢?

下面是關于mod運算的數學定義:

clip_image001

上面是截圖, "取下界"符號找不到如何輸入(word中粘貼過來后亂碼). 下面是使用"L"和"J"替換上圖的"取下界"符號:

x mod y = x - y L x / y J

上面公式的意思是:

x mod y等于 x 減去 y 乘上 x與y的商的下界.

以 -3 mod 2 舉例:

-3 mod 2

= -3 - 2xL -3/2 J

= -3 - 2xL-1.5J

= -3 - 2x(-2)

= -3 + 4 = 1

所以:

(-2) mod 12 = 12-2=10

(-4) mod 12 = 12-4 = 8

(-5) mod 12 = 12 - 5 = 7

 

開始證明

再回到時鐘的問題上:

回撥2小時 = 前撥10小時

回撥4小時 = 前撥8小時

回撥5小時= 前撥7小時

注意, 這里發現的規律!

結合上面學到的同余的概念.實際上:

(-2) mod 12 = 10

10 mod 12 = 10

-2與10是同余的.

(-4) mod 12 = 8

8 mod 12 = 8

-4與8是同余的.

距離成功越來越近了. 要實現用正數替代負數, 只需要運用同余數的兩個定理:

反身性:

a ≡ a (mod m)

這個定理是很顯而易見的.

線性運算定理:

如果a ≡ b (mod m),c ≡ d (mod m) 那么:

(1)a ± c ≡ b ± d (mod m)

(2)a * c ≡ b * d (mod m)

如果想看這個定理的證明, 請看:http://baike.baidu.com/view/79282.htm

所以:

7 ≡ 7 (mod 12)

(-2) ≡ 10 (mod 12)

7 -2 ≡ 7 + 10 (mod 12)

現在我們為一個負數, 找到了它的正數同余數. 但是并不是7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即計算結果的余數相等.

接下來回到二進制的問題上, 看一下: 2-1=1的問題.

2-1=2+(-1) = [0000 0010] + [1000 0001]= [0000 0010] + [1111 1110]

先到這一步, -1的反碼表示是1111 1110. 如果這里將[1111 1110]認為是原碼, 則[1111 1110]原 = -126, 這里將符號位除去, 即認為是126.

發現有如下規律:

(-1) mod 127 = 126

126 mod 127 = 126

即:

(-1) ≡ 126 (mod 127)

2-1 ≡ 2+126 (mod 127)

2-1 與 2+126的余數結果是相同的! 而這個余數, 正式我們的期望的計算結果: 2-1=1

所以說一個數的反碼, 實際上是這個數對于一個膜的同余數. 而這個膜并不是我們的二進制, 而是所能表示的最大值! 這就和鐘表一樣, 轉了一圈后總能找到在可表示范圍內的一個正確的數值!

而2+126很顯然相當于鐘表轉過了一輪, 而因為符號位是參與計算的, 正好和溢出的最高位形成正確的運算結果.

既然反碼可以將減法變成加法, 那么現在計算機使用的補碼呢? 為什么在反碼的基礎上加1, 還能得到正確的結果?

2-1=2+(-1) = [0000 0010] + [1000 0001] = [0000 0010] + [1111 1111]

如果把[1111 1111]當成原碼, 去除符號位, 則:

[0111 1111] = 127

其實, 在反碼的基礎上+1, 只是相當于增加了膜的值:

(-1) mod 128 = 127

127 mod 128 = 127

2-1 ≡ 2+127 (mod 128)

此時, 表盤相當于每128個刻度轉一輪. 所以用補碼表示的運算結果最小值和最大值應該是[-128, 128].

但是由于0的特殊情況, 沒有辦法表示128, 所以補碼的取值范圍是[-128, 127]

本人一直不善于數學, 所以如果文中有不對的地方請大家多多包含, 多多指點!

注釋:
 

1、文章第三部分提到“用反碼計算減法, 結果的真值部分是正確的. 而唯一的問題其實就出現在"0"這個特殊的數值上” ,這是不對的。
用反碼計算減法(特指兩正數相減),只有當結果是負數或0時,結果的真值部分才是正確的,當結果是正數時就不對了,比如:2-1=[00000010]反+[11111110]反=[00000000]反=0,這顯然是錯誤的。所以反碼用于計算的話,問題不止是‘0’的表示。

2、文章最后對同余的講解非常清楚,但是用同余的觀點解釋反碼和補碼的運算卻是有點偏差的。
既然計算機在運算時并不辨別符號位,那么它其實是把這些二進制數統一看作無符號數進行計算的,所以在用同余理論時把反碼、補碼同無符號數進行比較才能解釋的通。
對于8位機,計算機的循環計數周期為256,所以計算機對無符號數運算后的結果實際是把真實結果對模256取余。在原碼、反碼、補碼中,只有補碼對應的無符號數與真值始終是關于256同余的,所以補碼計算的結果與真實結果相同(在沒有溢出的情況下)。

用原碼和反碼計算出錯的原因也可以這樣解釋。原碼就不用說了,反碼的話,正數的反碼對應的無符號數與真值是關于256同余的,而負數的反碼對應的無符號數卻與真值關于255同余,所以結果有可能出錯。在“1-1”這個例子中,結果的真值部分剛好正確是有些巧合在里面的,實際上兩個正數相減,如果結果為負數或0,結果所對應的真值都恰好正確,但只要結果是正數就不對了,這可以從反碼與真值的關系推斷出來。


關于二進制、原碼、反碼、補碼科普說明 

原碼就是原來的表示方法

反碼是除符號位(最高位)外取反

補碼=反碼+1

以前學習二進制編碼時,老師講了一堆堆的什么原碼啊反碼啊補碼啊xxxx轉換啊,還有負數的表示方式啊 總是記不零清,終于從網上找到了一種比較好的講解方式,保存再share一下,不過為了系統化講解,又找來了一些編碼的基礎知識,如果只想看負數編碼記憶法,請跳轉到

1.如果你不知道二進制怎么編碼,請繼續,否則請跳到2

    1字節 = 8位,所以它能表示的最大數當然是8位都是1(既然2進制的數只能是0或1,如果是我們常見的10進制,那就8位都為9,這樣說,你該懂了?)

1字節的二進制數中,最大的數:11111111。

    這個數的大小是多少呢?讓我們來把它轉換為十進制數。

    無論是什么進制,都是左邊是高位,右邊是低位。10進制是我們非常習慣的計數方式,第一位代表有幾個1(即幾個100),第二位代表有幾個10(即幾個101),第三位代表有幾個100(即有幾個102)…,用小學課本上的說法就是:個位上的數表示幾個1,十位上的數表示向個10,百位上的數表示幾個100……

    同理可證,二進制數則是:第1位數表示幾個1 (20),第2位數表示幾個2(21),第3位數表示幾個4(22),第4位數表示向個8(23)……

    以前我們知道1個字節有8位,現在通過計算,我們又得知:1個字節可以表達的最大的數是255,也就是說表示0~255這256個數。

     那么兩個字節(雙字節數)呢?雙字節共16位。 1111111111111111,這個數并不大,但長得有點眼暈,從現在起,我們要學會這樣來表達二制數:

1111 1111 1111 1111,即每4位隔一空格。

雙字節數最大值為:

1 * 215 + 1 *214 + 1* 213 + 1 * 212 + 1 * 211 + 1 * 210 + …… + 1 * 22 + 1 * 21 + 1* 20 = 65535

    很自然,我們可以想到,一種數據類型允許的最大值,和它的位數有關。具體的計算方法方法是,如果它有n位,那么最大值就是:

n位二進制數的最大值:1 * 2(n-1) + 1 * 2(n-2) + ... + 1 * 20

2、理解有符號數和無符號數

負數在計算機中如何表示呢?這一點,你可能聽過兩種不同的回答。

一 種是教科書,它會告訴你:計算機用&ldquo;補碼&rdquo;表示負數。可是有關&ldquo;補碼&rdquo;的概念一說就得一節課,這一些我們需要在第6章中用一章的篇幅講2進制的一切。再 者,用&ldquo;補碼&rdquo;表示負數,其實是一種公式,公式的作用在于告訴你,想得到問題的答案,應該如何計算。卻并沒有告訴你為什么用這個公式就可以得到答案? -----我就是被這個弄混淆的>_<

另 一種是一些程序員告訴你的:用二進制數的最高位表示符號,最高位是0,表示正數,最高位是1,表示負數。這種說法本身沒錯,可是如果沒有下文,那么它就是 錯的。至少它不能解釋,為什么字符類型的-1用二進制表示是&ldquo;1111 1111&rdquo;(16進制為FF);而不是我們更能理解的&ldquo;1000 0001&rdquo;。(為什么說后者更好理解呢?因為既然說最高位是1時表示負數,那1000 0001不是正好是-1嗎?-----re!當初偶就是這么想的,so一直在腦中打架,越打越混淆=,=)。

讓我們從頭說起。

2.1、你自已決定是否需要有正負。

就像我們必須決定某個量使用整數還是實數,使用多大的范圍數一樣,我們必須自已決定某個量是否需要正負。如果這個量不會有負值,那么我們可以定它為帶正負的類型。

在計算機中,可以區分正負的類型,稱為有符類型,無正負的類型(只有正值),稱為無符類型。

數值類型分為整型或實型,其中整型又分為無符類型或有符類型,而實型則只有有符類型。

字符類型也分為有符和無符類型。

比如有兩個量,年齡和庫存,我們可以定前者為無符的字符類型,后者定為有符的整數類型。

2、使用二制數中的最高位表示正負。

首先得知道最高位是哪一位?1個字節的類型,如字符類型,最高位是第7位,2個字節的數,最高位是第15位,4個字節的數,最高位是第31位。不同長度的數值類型,其最高位也就不同,但總是最左邊的那位(如下示意)。字符類型固定是1個字節,所以最高位總是第7位。

(紅色為最高位)

單字節數: 1111 1111

雙字節數: 1111 1111 1111 1111

四字節數: 1111 1111 1111 1111 1111 1111 1111 1111

當我們指定一個數量是無符號類型時,那么其最高位的1或0,和其它位一樣,用來表示該數的大小。

當我們指定一個數量是有符號類型時,此時,最高數稱為&ldquo;符號位&rdquo;。為1時,表示該數為負值,為0時表示為正值。

 3、無符號數和有符號數的范圍區別。

無符號數中,所有的位都用于直接表示該值的大小。有符號數中最高位用于表示正負,所以,當為正值時,該數的最大值就會變小。我們舉一個字節的數值對比:

無符號數: 1111 1111   值:255 1* 27 + 1* 26 + 1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20

有符號數: 0111 1111   值:127         1* 26 + 1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20

  同樣是一個字節,無符號數的最大值是255,而有符號數的最大值是127。原因是有符號數中的最高位被挪去表示符號了。并且,我們知道,最高位的權值也是最高的(對于1字節數來說是2的7次方=128),所以僅僅少于一位,最大值一下子減半。

不過,有符號數的長處是它可以表示負數。因此,雖然它的在最大值縮水了,卻在負值的方向出現了伸展。我們仍一個字節的數值對比:

無符號數:                       0 ----------------- 255

有符號數:        -128 --------- 0 ---------- 127

 

同樣是一個字節,無符號的最小值是 0 ,而有符號數的最小值是-128。所以二者能表達的不同的數值的個數都一樣是256個。只不過前者表達的是0到255這256個數,后者表達的是-128到+127這256個數。

一個有符號的數據類型的最小值是如何計算出來的呢?

有符號的數據類型的最大值的計算方法完全和無符號一樣,只不過它少了一個最高位(見第3點)。但在負值范圍內,數值的計算方法不能直接使用1* 26 + 1* 25 的公式進行轉換。在計算機中,負數除為最高位為1以外,還采用補碼形式進行表達。所以在計算其值前,需要對補碼進行還原。這里,先直觀地看一眼補碼的形式:

以我們原有的數學經驗,在10進制中:1 表示正1,而加上負號:-1 表示和1相對的負值。

那么,我們會很容易認為在2進制中(1個字節): 0000 0001 表示正1,則高位為1后:1000 0001應該表示-1。

然而,事實上計算機中的規定有些相反,請看下表:

 

 

二進制值(1字節)十進制值
1000 0000紅色的1代表負數藍色的是補碼(補碼=反碼+1)-128
1000 0001藍色部分代表多大的值?:將補碼還原為原碼-127想化成負數?:先減去1按位取反
1000 0010還原方法:補碼-1再取反-126
1000 0011-125
......
1111 1110-2
1111 1111-1 


首先我們看到,從-1到-128,其二進制的最高位都是1(表中標為紅色),正如我們前面的學。

然后我們有些奇怪地發現,1000 0000 并沒有拿來表示 -0;而1000 0001也不是拿來直觀地表示-1。事實上,-1 用1111 1111來表示。

怎么理解這個問題呢?先得問一句是-1大還是-128大

當 然是 -1 大。-1是最大的負整數。以此對應,計算機中無論是字符類型,或者是整數類型,也無論這個整數是幾個字節。它都用全1來表示 -1。比如一個字節的數值中:1111 1111表示-1,那么,1111 1111 - 1 是什么呢?和現實中的計算結果完全一致。1111 1111 - 1 = 1111 1110,而1111 1110就是-2。這樣一直減下去,當減到只剩最高位用于表示符號的1以外,其它低位全為0時,就是最小的負值了,在一字節中,最小的負值是1000 0000,也就是-128。

--------小米批注:就是這部分藍色的文字,讓我終于能記清楚-1的編碼方式了,汗=。=

我們以-1為例,來看看不同字節數的整數中,如何表達-1這個數:

 

字節數二進制值十進制值
單字節數1111 1111紅色表示負數藍色部分的補碼為值1-1
負數:原碼就是原來的表示方法、反碼是除符號位(最高位)外取反、補碼=反碼+1雙字節數1111 1111 1111 1111-1
四字節數1111 1111 1111 1111 1111 1111 1111 1111-1

 可 能有同學這時會混了:為什么 1111 1111 有時表示255,有時又表示-1?所以我再強調一下本節前面所說的第2點:你自已決定一個數是有符號還是無符號的。寫程序時,指定一個量是有符號的,那么 當這個量的二進制各位上都是1時,它表示的數就是-1;相反,如果事選聲明這個量是無符號的,此時它表示的就是該量允許的最大值,對于一個字節的數來說, 最大值就是255。

ok 摘抄暫告段落,其實原文對于c的一些基礎數據類型知識介紹的非常詳細,8過太長了,摘到我需要的內容后就沒全帖過來,如果有需要學習的同學,建議參見原文:)

節選自:《什么叫機器數?計算機為什么要采用補碼?

    在計算機內部,所有信息都是用二進制數串的形式表示的。整數通常都有正負之分,計算機中的整數分為無符號的和帶符號的。無符號的整數用來表示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編碼 的唯一性。

    整數和0的原碼、反碼和補碼都相同,下面介紹手工快速求負數補碼的方法。這個方法在教材的第8頁已經提到了,這里再寫出來以便能引起大家的注意。其方法如下:

    先寫出該負數的相反數(正數),再將該正數的二進制形式寫出來,然后對這個二進制位串按位取反,即若是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,&hellip;。

    在數學中,用&ldquo;同余&rdquo;概念描述上述關系,即兩整數A、B用同一個正整數M (M稱為模)去除而余數相等,則稱A、B對M同余,記作:

       A=B     (MOD M)

    具有同余關系的兩個數為互補關系,其中一個稱為另一個的補碼。當M=12時,-5和+7,-4和+8,-3和+9就是同余的,它們互為補碼。

    從同余的概念和上述時鐘的例子,不難得出結論:對于某一確定的模,用某數減去小于模的另一個數,總可以用加上&ldquo;模減去該數絕對值的差&rdquo;來代替。因此,在有模運算中,減法就可以化作加法來做。

    可以看出,補碼的加法運算所依據的基本關系為:

[x]補+ [y]補= [x+y]補

    補碼減法所依據的基本關系式:

[x-y]補 =[x+(-y)]補= [x]補+ [-y]補

    至于加法運算為什么比減法運算易于實現以及CPU如何實現各種算術運算等問題,則需要通過對數字電路的學習來理解CPU的運算器的硬件實現問題的相關內容了。