1. 程式人生 > >談談我眼中的補碼

談談我眼中的補碼

導讀:補碼是如何產生的、計算機如何表示負數。

1.前提認知

(1)計算機中只有加法器,加減法使用的都是加法器,同時計算機通過加法器左移累加實現乘法運算、右移累減實現除法運算。

(2)補碼是一種編碼格式,它不是真實的數字。

我在之前的文章《從電晶體開始聊聊計算機為什麼採用二進位制》中說過計算機中所有機器碼“0101”實際上是高低電平的不同排列組合。

至於這些“0101”數字真正表示的是什麼人類可讀的資訊,是由電腦科學家制定的標準決定的。

這個標準就是我們常說的“編碼格式”或“編碼規則”,比如“0000_0001”在某種標準下表示現實世界十進位制1,但是在另一種標準下可以表示漢字“我”,在另一種標準下表示“A”。

所以,學習原碼、補碼時不要認為它們是數字,它們並沒有表示實際大小的意義。

(3)如下約定:“49-9=40”這個等式中49是被減數,9是減數。

2.補碼的實質

2.1.補碼的引入

假如我們面對的是一臺十進位制的2bit計算機,即這個計算機最多能儲存兩位數。

(1)那麼如何讓9變為0?

第一種方式是9-9,得數為0;

第二種方式是9+91,得數也為0。因為9+91=100,而2bit的計算機無法記錄百位數1,所以得到0。

從這裡可以發現一個規律,對於2bit的計算機來說,-9的計算效果相當於+91。

下面是對“49-9”按照這種計算效果進行計算:

49-9

=49+91

=140

因為3bit的140超出儲存空間,所以要捨去百位的1,得數為40,即49-9=40。

(2)同樣一臺十進位制的2bit計算機,我們可以計算一下“30-20”。

對於“20”這個數字來說,它要想變為0,要麼減去20,要麼加上80,所以“-20”的計算效果與“+80”相同。

接下來計算一下30-20:

30-20

=30+80

=110

捨去最高位1,得數10,即30-20等於10。

從上面的這兩個例子就可以看出對於一臺十進位制的2bit計算機來說,減法可以通過加法來實現。

這裡產生兩個問題:(1)“減數”和替換它的“加數”之間有什麼樣的對應關係,即如何根據減數確定加數;

(2)為什麼減法可以使用加法替代。

2.2.加數是減數的補碼

對於“49-9=49+91”而言,減數9加上91正好為100,同樣“30-20=30+80”中減數20加上80也是100。

這不是巧合,而是一種計算方式。

對於一臺十進位制的2bit計算機,這裡面和減數一起加起來得到100的那個數就是減數的“補碼”,減法計算其實就是加上那個減數的補碼。

2.3.為什麼減法可以使用加法替代

在回答這個問題之前,先搞清楚對於一臺十進位制的2bit計算機,為什麼要以100為補碼計算的標準呢?

原因很簡單,因為2bit計算機只能儲存2位數,100這個3bit數字實際上就是00,數字當加到100時,自動減少100。

換句話說,對於2bit的十進位制計算機來說,遇見100就清零,我這裡簡記為“遇百變零”,這就是一個減法,只不過是一次就固定的減100。

計算機可以藉助這個特性實現減法。

比如“30-20”是在30的基礎上減掉20,我們“遇百變零”是減100,而此處只要減去20,多減去100,那麼我們就加上80。

所以“30-20=30+80”。

這就是為什麼減法可以使用加法替代。

進而也可以認識到,減數與其補碼兩個數相加之和會將所有位數清零。

2.4.減數補碼的計算

上面已經說過:減數與其補碼兩個數相加之和會將計算機所有位數清零。

這就是減數的補碼的計算方式。

對於十進位制計算機來說,2bit計算機,減數 1的補碼就是99;4bit計算機,減數1的補碼是9999。

對於二進位制計算機來說,2bit計算機,減數01的補碼就是11;4bit計算機,減數0001的補碼就是1111.

到了這裡,我們用二進位制驗證一下,4bit計算機計算4-3。

3的二進位制是0011,3作為減數,所以要變為補碼與4相加,那麼我們先計算一下0011的補碼,如下表。

減數

 

0

0

1

1

補碼

 

1

1

0

1

清零

1

0

0

0

0

減數的二進位制數與其補碼之和會將4bit清零,可以看出0011的補碼是1101,也就是減數3參與加法器計算時使用的是“1101”編碼。

所以“4-3”在計算機內就是“0100+1101”,結果為10001,最高位無法儲存、捨去,結果為0001,如下表。

4的補碼

 

0

1

0

0

-3的補碼

 

1

1

0

1

1

0

0

0

1

即4-3的計算結果為0001,轉換為十進位制,就是1。

到這裡,我們暫停,先回憶一下:計算機內的減法計算實質上是被減數加上減數的補碼。比如49-9=49+91=40.

對於N位(bit)計算機而言,一個減數與其補碼之和可以使N位清零。

減數就是我們現實生活中人類可讀的數字,補碼是計算機識別的編碼符號。

由減數轉化為補碼這個過程稱為編碼,如實際數字-9轉換為補碼91就是編碼;

由補碼轉換為減數這個過程稱為解碼,如補碼91轉換為實際數字-9就是解碼。

3.補碼如何表示負數

本篇文章的兩個知識點,補碼的計算已經說完了。

下面說下一個知識點,補碼錶示負數的規律。

3.1.補碼一分為二

因為計算機內沒有減號、負號,科學家為了表示負數,就將數字區間一分為二,一半表示正數,另一半表示負數。

同樣以十進位制的2bit計算機作為說明,2bit計算機能夠儲存00到99一共100個數字。

不對!應該是00到99一共100個補碼。

計算機識別的不是人類可讀資訊,而是這些可讀資訊轉換的編碼,一定要有這種認知!

科學家將00到49這50個補碼作為正數,而且和實際數字一一對應,比如00表示實際的0,49對應實際的49。

之後將50到99這50個補碼作為負數,但不是50表示實際數字-1,而是99表示實際數字的-1,50表示實際數字-50。

負數和補碼之間之所以採用這種對映方式,還是因為“補碼”這種編碼格式:負數的絕對值(也就是減法中的減數)與其補碼之和會使計算機所有位數清零。

比如-1的補碼就是99,-50的補碼是50。

反過來想(也就是解碼),補碼99表示實際數字-1,補碼50表示實際數字-50.

總之,不論編碼還是解碼,使用的都是補碼的規則:負數絕對值與補碼之和清零所有位。

到這裡你可能想明白了為什麼8bit二進位制計算機內補碼1111_1111表示-1,為什麼補碼1000_0000是最大負數-128而不是-0了吧。

這樣一來,00到99這100個補碼就表示了實際數字-50到49。

二進位制計算機也是如此,比如8bit計算機共有0000_0000到1111_1111一共256個補碼。

256個補碼一分為二,0000_0000到0111_1111共計128個補碼錶示正數,而且和實際數字一一對應。

比如補碼0000_0000表示實際數字0,0000_1000表示實際數字8,0111_1111表示實際數字127.

1000_0000到1111_1111共計128個補碼錶示負數,和實際負數之間採用補碼這種對映關係。

比如補碼1111_1111表示-1,因為1111_1111加上0000_0001清零;補碼1000_0000表示-128,因為1000_0000加上1000_0000清零。

如此一來,8bit二進位制計算機就可以表示-128到127這些實際大小的數字了。

在計算機中,8位帶符號二進位制數的取值範圍是[-128, 127],比如Java中byte型別。

這與我們上面的解釋對應上了。

同時也澄清了一個誤會,計算機最高位1表示負數,是因為1000_0000將256個補碼恰好一分為二,用1000_0000及以後的補碼錶示負數。

計算機對於最高位是1的數字並不是將首位1直接變為負號,而是通過補碼這種編碼將其整體解碼為負數。

所以不要將最高位的1與其它位的二進位制數分離開來,分別看待。

3.2.補碼的解碼

在之前的案例中,我們實現減法都是大數減去小數,如49-9,3-20,4-3.但是如果換成小數減去大數,好像就出問題了。

如果你沒有發現可以計算一下“9-49”。

9-49

=9+51

=60

竟然出現了“9-49=9+51=60”的情況?

9-49應該等於-40,怎麼是60呢?

原因很簡單,60是-40的補碼。

計算機只識別補碼60,之後就會解碼將其轉化為實際數字-40。

這時你可能想到了文章開篇說的一種認知——補碼只是一種編碼格式,它不是表示真正大小的數字。

此時60這個編碼對應的實際數字就是-40,即9-49=-40。

到了這裡,我們就瞭解了人類是如何給計算機賦予負號的含義。就是通過補碼的編碼與解碼。

4.總結

4.1.運算資料都是補碼形式

人類輸入的運算資訊在計算機中是以補碼的形式存在的。不論是加法中的加數,還是減法中的被減數、減數,還是運算結果。

你可能想到了“49-9=49+91=40”中的“40”其實也是補碼,只不過形式上和實際數字相同。

4.2.減法的執行過程

(1)減法中的被減數和減數首先按照補碼這種編碼格式轉換為補碼,被減數和補碼從形式上看一模一樣,減數則是與其補碼之和清零。

(2)加法器執行加法。

(3)如果資料溢位,那麼就將剩下的資料解碼為實際數字;如果沒有溢位,就將這個結果解碼為實際數字。

以十進位制2bit計算機為例,49-9轉換為補碼49和91,之後加法器相加,溢位一位得到補碼40,解碼為實際數字40;

9-49轉換為補碼是9和51,之後加法器相加,沒有溢位得到補碼60,解碼為實際數字-40。

以上就是我對補碼的初步認識。