基本數(shù)據(jù)類型
計算機底層存儲數(shù)據(jù)時使用的是二進制數(shù)字烈掠,但是計算機在存儲一個數(shù)字時并不是直接存儲該數(shù)字對應的二進制數(shù)字羞秤,而是存儲該數(shù)字對應二進制數(shù)字的補碼。所以接下來我們需要來了解一下原碼向叉、反碼和補碼锥腻。
- 機器數(shù):一個數(shù)在計算機的存儲形式是二進制數(shù),我們稱這些二進制數(shù)為機器數(shù)母谎,機器數(shù)是有符號,在計算機中用機器數(shù)的最高位存放符號位京革,0表示正數(shù)奇唤,1表示負數(shù)。
- 機器數(shù)的真值:因為帶有符號位匹摇,所以機器數(shù)的形式值不等于其真值咬扇,以機器數(shù)1000 0111為例,其真正表示的值為-7廊勃,而形式值為135懈贺。將帶符號的機器數(shù)的真正表示的值稱為機器數(shù)的真值。
原碼
原碼的表示與機器數(shù)真值表示的一樣坡垫,即用第一位表示符號梭灿,其余位表示數(shù)值,例如的十進制的的正負1冰悠,用8位二進制的原碼表示如下:
【+1】= 原:[ 0000 0001 ]
【-1】= 原:[ 1000 0001 ]
反碼
反碼的表示方法為:
- 正數(shù)的反碼是其原碼本身堡妒。
- 負數(shù)的反碼是在其原碼的基礎上,符號位不變溉卓,其余各位取反皮迟。
【+1】= 原: [ 0000 0001 ] = 反:[ 0000 0001 ]
【-1】 = 原:[ 1000 0001 ] = 反:[ 1111 1110 ]
補碼
補碼的表示方法為:
- 正數(shù)的補碼是其原碼本身。
- 負數(shù)的補碼是在其原碼的基礎上桑寨,符號位不變伏尼,其余各位取反后加1(即在反碼的基礎上加1)。
【+1】= 原: [ 0000 0001 ] = 反:[ 0000 0001 ] = 補:[ 0000 0001 ]
【-1】 = 原:[ 1000 0001 ] = 反:[ 1111 1110 ] = 補:[ 1111 1111 ]
數(shù)據(jù)在計算機中的存儲形式
計算機實際只存儲補碼尉尾, 所以原碼轉(zhuǎn)換為補碼的過程爆阶,也可以理解為數(shù)據(jù)存儲到計算機內(nèi)存中的過程:
在原、反、補碼中扰她,正數(shù)的表示是一模一樣的兽掰,而負數(shù)的表示是不相同的,所以對于負數(shù)的補碼來說徒役,我們是不能直接用進制轉(zhuǎn)換將其轉(zhuǎn)換為十進制數(shù)值的孽尽,因為這樣是得不到計算機真正存儲的十進制數(shù)的,所以應該將其轉(zhuǎn)換為原碼后忧勿,再將轉(zhuǎn)換得到的原碼進行進制轉(zhuǎn)換為十進制數(shù)杉女。(機器數(shù)包含符號位)
問題:為何使用原碼、反碼鸳吸、補碼
我們上面說過熏挎,原碼、反碼晌砾、補碼的表示對于正數(shù)來說都是一樣的坎拐,而對于負數(shù)來說,三種碼的表示確是完全不同的养匈,那大家是否會有個疑問:如果原碼才是我們?nèi)祟惪梢宰R別并用于直接計算的表示方式哼勇,那為什么還會有反碼和補碼?計算機直接存儲原碼不就完事了呕乎?
在解決這些問題前积担,我們先來了解計算機的底層概念,我們?nèi)四X可以很輕松的知道機器數(shù)的第一位是符號位猬仁,但對于計算機基礎電路設計來說判別第一位是符號位是非常難和復雜的事情帝璧,為了讓計算機底層設計更加簡單,人們開始探索將符號位參與運算湿刽,并且采用只保留加法的方法的烁,我們知道減去一個數(shù),等于加上這個數(shù)的負數(shù)叭爱,即:1-1 = 1 + (-1) = 0撮躁,這樣讓計算機運算就更加簡單了,并且也讓符號位參與到運算中去买雾。
1.使用原碼運算
計算十進制表達式:1-1 = 0把曼;
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 原:[ 1000 0010 ] = -2
如果用原碼表示,讓符號位也參與計算漓穿,對于減法來說嗤军,結果是不正確的。這也是計算機內(nèi)部在存儲數(shù)據(jù)時不使用原碼的原因晃危,為了解決這一問題叙赚,出現(xiàn)了反碼老客。
2.使用反碼運算
計算十進制表達式:1-1 = 0
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 反:[ 0000 0001 ] + 反:[ 1111 1110 ]
= 反:[ 1111 1111 ] = 原: [ 1000 0000 ] = -0
通過計算我們發(fā)現(xiàn)用反碼計算減法,結果的真值部分是正確的震叮。而唯一的問題出現(xiàn)在"0"這個特殊的數(shù)值上胧砰,雖然人們理解上+0和-0是一樣的,但是0帶符號是沒有任何意義的苇瓣,而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0尉间。為了解決這一問題,出現(xiàn)了補碼击罪。
3.使用補碼運算
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 補:[ 0000 0001 ] + 補:[ 1111 1111 ]
= 補: [ 0000 0000 ] = 原: [ 0000 0000 ] = 0
這樣0用[0000 0000]表示哲嘲,而以前出現(xiàn)問題的-0則不存在了,而且人們還發(fā)現(xiàn)可以用[1000 0000]表示-128媳禁,-128的推算過程如下:
(-1) + (-127) = -128
= 原:[1000 0001] + 原:[ 1111 1111 ]
= 補:[ 1111 1111 ] + 補:[ 1000 0001 ]
= 補:[ 1000 0000 ]
注意:因為實際上是使用以前的-0的補碼來表示-128眠副,所以-128并沒有原碼和反碼表示,只要補碼是[1000 0000]竣稽,其十進制數(shù)值就為-128囱怕。
因為補碼能多存儲一個-128,而且在計算機底層中存儲的是補碼丧枪,所以在計算機中一個8位的二進制數(shù)的存儲范圍是用補碼表示的[-128,127]光涂,而不是用原碼或反碼表示的[-127,127]。這也可以解釋為什么計算機中一個字節(jié)的取值范圍是[-128,127]拧烦。
這樣也能夠回答我們開始提出的問題了,原碼钝计、反碼恋博、補碼的使用,是人們?yōu)榱俗尫栁荒軈⑴c運算并讓計算機底層運算更加簡單而設計出來的數(shù)據(jù)存儲表示方式私恬。
本文轉(zhuǎn)至微信公眾號:【平兄聊Java】