深入理解計算機中的原碼、補碼、反碼

基本數據類型



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

  • 機器數:一個數在計算機的存儲形式是二進制數,我們稱這些二進制數為機器數,機器數是有符號,在計算機中用機器數的最高位存放符號位,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 ]


數據在計算機中的存儲形式

計算機實際只存儲補碼, 所以原碼轉換為補碼的過程,也可以理解為數據存儲到計算機內存中的過程:

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

🔴pingxiong:說到這你應該懂得了計算機底層是如何存儲數據的了吧,但我們不能止步於此,我們還應該知道為什麼要這麼存儲?


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

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

在解決這些問題前,我們先來了解計算機的底層概念,我們人腦可以很輕鬆的知道機器數的第一位是符號位,但對於計算機基礎電路設計來說判別第一位是符號位是非常難和複雜的事情,為了讓計算機底層設計更加簡單,人們開始探索將符號位參與運算,並且採用只保留加法的方法,我們知道減去一個數,等於加上這個數的負數,即: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]。

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


更多精彩內容敬請關注微信公眾號:【平兄聊Java】