Math.abs(Integer.MIN_VALUE)問題分析

日常刷題中,然後有個地方是要求將當前數變成絕對值纔可以使用;然後開開心心寫了如下代碼:

long a = Math.abs(Integer.MIN_VALUE);
System.out.println(a);

結果結果卻讓我大跌眼鏡。但是一番分析下來倒是很有意思


點開源碼(JDK1.8環境下)

這段話翻譯過來就是,如果abs方法輸入參數爲正數,就返回那個值;如果未負數,就返回這個負數的對應絕對值;但是如果輸入值爲Integer.MIN_VALUE時;就返回輸入值

這樣看起來問題是解決了,但是身爲一個合格的程序員,怎麼可以不弄清楚原因呢。

1.原因分析

要講清上面發生的原因,就必須把幾個核心的問題都講清楚;

1.1 原碼

一開始人們是通過原碼來表示整數,整數有正負之分,便通過符號位+二進制的方式表示。(最高位(最左邊)取0表示正數,取1表示負數。然後加上對應的二進制。

+1 = 0000 0001
-1 = 1000 0001

1.2 反碼

正數的反碼是其本身
負數的反碼是符號位不變 ,其他位都變爲反

[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反

1.3 補碼

正數的補碼就是其本身
負數的補碼是在其原碼的基礎上, 符號位不變, 其餘各位取反, 最後+1. (即在反碼的基礎上+1)

[+1] = [00000001]原 = [00000001]反 = [00000001]補
[-1] = [10000001]原 = [11111110]反 = [11111111]補

那麼爲何要使用補碼呢?

因爲計算機中沒有減法的概念,對應減法 a-b = a+(-b);

反碼的方式
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
1 - 1 = 1 + (-1) = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
補碼的方式
1 - 1 = 1 + (-1) = [0000 0001]補 +[1111 1111]補 = [0000 0000]補=0

所以這裏如果1.8的jdk不限制,就容易導致結果錯誤;可以理解爲

MIN_VALUE[反] = 0x80000000 = 10....0(中間29個0)= 1......1(中間30個1)
MIN_VALUE[補] = 0x80000000 = 10....0(中間29個0) = 1......1(中間30個1)+1 = 0......0(中間30個1)

所以 這裏錯誤了;而且可以發現超出限制後,會形成一個循環

所以可以理解爲爲了防止這樣的循環發生,JDK1.8出現這個保護的模式;而一切的發生源頭就是補碼導致

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章