天天看點

原碼/反碼/補碼的由來,為什麼計算機底層使用補碼存儲整型

計算機底層存儲資料時使用的是二進制數字,但是計算機在存儲一個數字時并不是直接存儲該數字對應的二進制數字,而是存儲該數字對應二進制數字的補碼。是以接下來我們需要來了解一下原碼、反碼和補碼。

  • 機器數:一個數在計算機的存儲形式是二進制數,我們稱這些二進制數為機器數,機器數是有符号,在計算機中用機器數的最高位存放符号位,0表示正數,1表示負數。
  • 機器數的真值:因為帶有符号位,是以機器數的形式值不等于其真值,以機器數1000 0111為例,其真正表示的值為-7,而形式值為135。将帶符号的機器數的真正表示的值稱為機器數的真值。

原碼

原碼的表示與機器數真值表示的一樣,即用第一位表示符号,其餘位表示數值,例如的十進制的的正負1,用8位二進制的原碼表示如下:

【+1】= 原:[ 0000 0001 ]

【-1】= 原:[ 1000 0001 ]

反碼

反碼的表示方法為:

正數的反碼是其原碼本身。

負數的反碼是在其原碼的基礎上,符号位不變,其餘各位取反。

【+1】= 原: [ 0000 0001 ] = 反:[ 0000 0001 ]

【-1】 = 原:[ 1000 0001 ] = 反:[ 1111 1110 ]

補碼

補碼的表示方法為:

正數的補碼是其原碼本身。

負數的補碼是在其原碼的基礎上,符号位不變,其餘各位取反後加1(即在反碼的基礎上加1)。

【+1】= 原: [ 0000 0001 ] = 反:[ 0000 0001 ] = 補:[ 0000 0001 ]

【-1】 = 原:[ 1000 0001 ] = 反:[ 1111 1110 ] = 補:[ 1111 1111 ]

資料在計算機中的存儲形式

計算機實際隻存儲補碼, 是以原碼轉換為補碼的過程,也可以了解為資料存儲到計算機記憶體中的過程:

在原、反、補碼中,正數的表示是一模一樣的,而負數的表示是不相同的,是以對于負數的補碼來說,我們是不能直接用進制轉換将其轉換為十進制數值的,因為這樣是得不到計算機真正存儲的十進制數的,是以應該将其轉換為原碼後,再将轉換得到的原碼進行進制轉換為十進制數。(機器數包含符号位)

問題:為何使用原碼、反碼、補碼

我們上面說過,原碼、反碼、補碼的表示對于正數來說都是一樣的,而對于負數來說,三種碼的表示确是完全不同的,那大家是否會有個疑問:如果原碼才是我們人類可以識别并用于直接計算的表示方式,那為什麼還會有反碼和補碼?計算機直接存儲原碼不就完事了?

在解決這些問題前,我們先來了解計算機的底層概念,我們人腦可以很輕松的知道機器數的第一位是符号位,但對于計算機基礎電路設計來說判别第一位是符号位是非常難和複雜的事情,為了讓計算機底層設計更加簡單,人們開始探索将符号位參與運算,并且采用隻保留加法的方法,我們知道減去一個數,等于加上這個數的負數,即:1-1 = 1 + (-1) = 0,這樣讓計算機運算就更加簡單了,并且也讓符号位參與到運算中去。

1.使用原碼運算

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

1 - 1 = 1 + (-1)

= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]

= 原:[ 1000 0010 ] = -2

如果用原碼表示,讓符号位也參與計算,對于減法來說,結果是不正确的。這也是計算機内部在存儲資料時不使用原碼的原因,為了解決這一問題,出現了反碼。

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。為了解決這一問題,出現了補碼。

3.使用補碼運算

1 - 1 = 1 + (-1)

= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]

= 補:[ 0000 0001 ] + 補:[ 1111 1111 ]

= 補: [ 0000 0000 ] = 原: [ 0000 0000 ] = 0

這樣0用[0000 0000]表示,而以前出現問題的-0則不存在了,而且人們還發現可以用[1000 0000]表示-128,-128的推算過程如下:

(-1) + (-127) = -128

= 原:[1000 0001] + 原:[ 1111 1111 ]

= 補:[ 1111 1111 ] + 補:[ 1000 0001 ]

= 補:[ 1000 0000 ]

注意:因為實際上是使用以前的-0的補碼來表示-128,是以-128并沒有原碼和反碼表示,隻要補碼是[1000 0000],其十進制數值就為-128。

因為補碼能多存儲一個-128,而且在計算機底層中存儲的是補碼,是以在計算機中一個8位的二進制數的存儲範圍是用補碼表示的[-128,127],而不是用原碼或反碼表示的[-127,127]。這也可以解釋為什麼計算機中一個位元組的取值範圍是[-128,127]。

這樣也能夠回答我們開始提出的問題了,原碼、反碼、補碼的使用,是人們為了讓符号位能參與運算并讓計算機底層運算更加簡單而設計出來的資料存儲表示方式。

計算機硬體内部,整數用補碼表示,當兩個數相加時,這兩個數直接送入加法器相加;兩數相減時,用反相器求減數的反碼,把此反碼和被減數送入加法器,并設定個位的初始進位為1,,即求減數的補數再與被減數相加,加運算的結果就是原兩數相減的結果。是以,計算機内隻用設定加法器就能做加減運算了。