爲什麼Integer.MIN_VALUE沒有對應的正數


爲什麼 Java 中的 Integer.MAX_VALUE = 0x7fffffffInteger.MIN_VALUE = 0x80000000 ? 解決了這個問題,自然也就解決了 爲什麼 Integer.MIN_VALUE 沒有對應的正數


不難理解上面的最大值(Integer.MAX_VALUE)以及最小值(Integer.MIN_VALUE)是 16進制 的表示,轉換成對應的十進制爲:

  • Integer.MAX_VALUE = 2 ^ 31 - 1
  • Integer.MIN_VALUE = -2 ^ 31

在 Java 中,short、int、long 在內存中採用了二進制補碼的形式表示,二進制補碼的好處是隻有一個零,沒有 “負零” 的概念,所以可以多存儲一個值。補碼的計算方式如下:

正數的補碼不變,負數的補碼爲符號位不變,其餘取反(反碼),最終加1,0 的補碼仍然爲 0;


迴歸到我們這裏,int 類型佔 32 位,所以轉換成對應的二進制爲(以下均簡寫最大值,最小值):

  • max = 0111 1111 1111 1111
  • min = 1000 0000 0000 0000

爲什麼 Integer.MAX_VALUE = 2 ^ 31 - 1

這個問題其實是二進制轉換爲十進制的問題,max = 0111 1111 1111 1111 = 2 ^ 0 + 2 ^ 1 + … + 2 ^ 30 (等比數列)= 2 ^ (n + 1) - 1 = 2 ^ 31 -1 。


爲什麼 Integer.MIN_VALUE = -2 ^ 31

這個非常好理解,min = 1000 0000 0000 0000 = - 2 ^ 31 ,那麼爲什麼 min = 1000 0000 0000 0000 呢?我們可以做一個這樣的推算:先看最大的負整數 -1 的二進制補碼形式爲 1000 0001 (中間省略了部分 0),之前說過在內存中採用的是補碼形式,所以我們採用倒推的形式推出原碼

1000 0001

-0000 0001

=1000 0000,再取反 ,就等於 1111 1111。所以 -1 的二進制形式爲 1111 1111 1111 1111(不省略中間 0 計算的結果)。不難推出 1000 0000 0000 0001 = - ( 2 ^ 31 - 1 ) ,這裏採用了十進制表示。之前有提到過補碼沒有 “負零” 的概念,所以可以多存儲一個值。那麼就是 1000 0000 0000 0000 這個值了,表示爲 十進制則爲
-2 ^ 31。

總結

出現以上問題的根本原因,在於系統中採用的是補碼的方式進行存儲。理解了補碼的特性,也就理解了爲什麼會出現上面的問題了。

這裏還有個有意思的關於 Java 的代碼:

int abs = Math.abs(Integer.MIN_VALUE );
int value = Integer.MIN_VALUE - 1;

上面求出的 abs 仍然爲 Integer.MIN_VALUE,value 爲 Integer_MAX_VALUE

你可以加上這樣的斷言去驗證:

assert Integer.MIN_VALUE == Math.abs(Integer.MIN_VALUE );
assert Integer.MIN_VALUE - 1 == Integer.MAX_VALUE;

至於爲什麼 abs 仍然爲 Integer.MIN_VALUE,其實絕對值計算可以看做 0 減去這個數,所以上面的計算過程如下(簡化了中間的 0):

0000 0000

-1000 0000

=1000 0000


而 value 會爲什麼會爲 Integer_MAX_VALUE ?這是因爲發生了 溢出 ,底層只會保留 32 位,計算過程如下:

1000 0000

-0000 0001

=0111 1111


現在,終於搞懂爲什麼了!
發佈了126 篇原創文章 · 獲贊 22 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章