爲什麼一個byte的存儲範圍是-128~127?

寫在前面:博主是一只經過實戰開發歷練後投身培訓事業的“小山豬”,暱稱取自動畫片《獅子王》中的“彭彭”,總是以樂觀、積極的心態對待周邊的事物。本人的技術路線從Java全棧工程師一路奔向大數據開發、數據挖掘領域,如今終有小成,願將昔日所獲與大家交流一二,希望對學習路上的你有所助益。同時,博主也想通過此次嘗試打造一個完善的技術圖書館,任何與文章技術點有關的異常、錯誤、注意事項均會在末尾列出,歡迎大家通過各種方式提供素材。

  • 對於文章中出現的任何錯誤請大家批評指出,一定及時修改。
  • 有任何想要討論和學習的問題可聯繫我:[email protected]
  • 發佈文章的風格因專欄而異,均自成體系,不足之處請大家指正。

爲什麼一個byte的存儲範圍是-128~127?

文本關鍵字:byte、字節、二進制位、反碼、補碼

一、byte

在計算機中,一個二進制位是最小的存儲單元,由於是二進制,所以能存儲的數字只能是0和1。顯然,如果我們直接去操作每個二進制位將是很麻煩的過程,所以在編程中我們直接使用的是其他的數據類型,如:byte、int、float。這些數據類型能夠使我們的數據存儲更加方便,我們只需要關心他們能夠存儲多大範圍和什麼樣類型的數據就可以了。
那麼一個byte,也就是我們所說的一字節,他所佔用的空間是8個二進制位。

  • 1 byte = 8 bit(比特)

這8個bit就是8個二進制位,其中有一個是符號位,剛好可以用0和1來代表正負。那麼這8個二進制位到底能夠表示多大範圍的數字呢?對於正數的進制轉換相信難不倒大家,也可以參考底部的相關文章,我們先來看一下負數在二進制下是如何表示和轉換的。

二、反碼與補碼

首先把公式立在這裏:

  • 正數的補碼 = 原碼 = 反碼
  • 負數的補碼 = 反碼 + 1

那麼首先什麼是原碼呢?很簡單,在我們不考慮符號的情況下,按照進制的轉換方法將一個十進制數轉換爲二進制數,再添加上相應的符號位就完成了。符號位出現在最前(左)面一位,0代表正數,1代表負數。

  • +3 -> 11 -> 根據符號和byte長度補全:0000 0011
  • -5 -> 101 -> 根據符號和byte長度補全:1000 0101

那麼爲什麼會提出反碼和補碼的概念呢?有兩個原因:

1. 反碼

保證在二進制下能夠正常的進行正負數間的運算。

首先我們來看一下如果直接使用原碼存儲,在進行正負數運算的時候會出現什麼樣的情況。5+(-3)=2,那麼在二進制下的運算也和十進制一樣,直接相加,該進位進位,但是符號位沒法直接參與運算,換句話說,讓計算機直接判斷算式最後的正負其實比較困難。
原碼計算:0000 0011 + 1000 0101 = 1000 1000,結果是:-8(不需要糾結最後的符號位應該取什麼,因爲在計算機中並沒有採用這種方法進行計算,只是舉例)。顯然,直接採用原碼計算的這種方式在正數下是沒問題的,但是在負數時就不適用了,所以我們需要重新定義一個規則對負數進行處理。
由於在正數下計算是沒問題的,那麼就可以規定:正數的反碼等於原碼,負數的反碼爲除去符號位,其他取反。

  • +3 -> 原碼:0000 0011 -> 反碼:0000 0011
  • -5 -> 原碼:1000 0101 -> 反碼:1111 1010

反碼計算後:1111 1101 -> 原碼:1000 0010 -> 十進制:-2。嗯,好像沒什麼問題了,但是當一個正數和一個負數的運算結果爲正數(如:+5和-3,大家可以自己驗證)或者恰好爲0時還是會有問題。

2. 補碼

+0和-0的衝突問題。

從相反數的概念我們可以知道,一個正數肯定存在一個與之對應的相反數,對於整數來說我們只要直接改變一下符號位就行了。But!這個0就很特殊,有一個耳熟能詳的概念:0的相反數還是0,這會直接導致進制的轉換不是一一對應的關係了。

  • +2 -> 原碼:0000 0010 -> 反碼:0000 0010
  • -2 -> 原碼:1000 0010 -> 反碼:1111 1101

反碼計算後:1111 1111 -> 原碼:1000 0000 -> 十進制:-0。結果貌似正確,但是在正數中:0000 0000也同樣代表0。那麼對於1000 0000,是不能直接被抹去的,那就讓它來代表一個特殊的數字吧:-128。
其實,特殊的不只是這一個數字,如對於Java中的short,佔用兩個字節,最高一位爲符號位,那麼就會出現這個數字:1000 0000 0000 0000,從原碼上看也是-0,對於int類型也是一樣,那麼這個問題就可以總結爲:符號位爲1,其他位均爲0,我們應該怎麼處理。
於是,爲了解決這一類問題,就有了補碼的概念:負數的補碼 = 反碼 + 1。我們用臨界位置的計算來進行舉例,如:(-2)+(-126)=-128。

  • -2 -> 原碼:1000 0010 -> 反碼:1111 1101 -> 補碼:1111 1110
  • -126 -> 原碼:1111 1110 -> 反碼:1000 0001 -> 補碼:1000 0010
  • 補碼運算結果:1000 0000(該類數字沒有原碼和反碼)

到此我們該敲個黑板,劃個重點了:在內存中都是使用補碼來進行計算的(整數類型)!

三、byte的數據範圍

明確了上面幾個概念,那麼byte的範圍應該就很清楚了。

  • 最大的正數:0111 1111 -> 2^7 - 1 = 127
  • 最大的負數:1000 0000 -> -2^7 = -128

對於其他正數類型的範圍也是如此:

  • Java中的short:2字節 -> -2^15 ~ 2^15 - 1
  • Java中的int:4字節 -> -2^31 ~ 2^31 - 1
  • Java中的long:8字節 -> -2^63 ~ 2^63 - 1

不同語言定義的數據類型在內存中佔用的字節數是不同的,而且也不需要直接記這些範圍,一般來說記字節就好。

  • 相關文章列表:

對進制轉換不清楚的同學可直擊:進制之間如何轉換

發佈了31 篇原創文章 · 獲贊 197 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章