返回錯誤值這個代碼:Math.abs爲Integer.MIN_VALUE的
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
它應該不會返回絕對值2147483648
?
返回錯誤值這個代碼:Math.abs爲Integer.MIN_VALUE的
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
它應該不會返回絕對值2147483648
?
Integer.MIN_VALUE
是-2147483648
,但32位整數可以包含的最大值是+2147483647
。嘗試在32位int中表示+2147483648
將有效「翻轉」至-2147483648
。這是因爲,當使用有符號整數時,+2147483648
和-2147483648
的二進制補碼二進制表示是相同的。但這不是問題,因爲+2147483648
被認爲超出範圍。
想了解更多有關此事的信息,您可能需要查看Wikipedia article on Two's complement。
以下是Java的醫生說了Math.abs()在javadoc:
注意,如果參數等於 Integer.MIN_VALUE值的,在 表示的最小負int值, 結果是相同的值,其中 是負值。
2147483648在java中不能存儲爲整數,其二進制表示與-2147483648相同。
但(int) 2147483648L == -2147483648
有一個負數沒有正的等值,所以沒有正值。您將看到與Long.MAX_VALUE相同的行爲。
一看就知道你期待,投Integer.MIN_VALUE
到long
結果:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
確實有可能的修復!然而,這並沒有解決'Math.abs'通過返回一個負數來違反直覺的事實:'Math.abs(Long.MIN_VALUE)== Long.MIN_VALUE' – 2013-06-17 09:38:42
@bernardpaulus,那麼,它應該做什麼,除了拋出'ArithmeticException'?此外,該行爲在API文檔中有明確記錄。 – Bombe 2013-06-21 08:39:11
有沒有很好的答案給你的問題...我只想指出,這種行爲是bug的一個來源,並不是通過使用'Math.abs(long)'來解決的。我在這裏對我的錯誤表示歉意:我認爲你提出使用'Math.abs(long)'作爲解決方法,當你將它展示爲一種簡單的方法來「查看提交者期望的結果」。抱歉。 – 2013-06-22 23:19:35
你指出的行爲的確,反直覺的。但是,此行爲是由javadoc for Math.abs(int)
指定的行爲:
如果參數不是負數,則會返回參數。 如果參數是否定的,則返回否定參數。
也就是說,Math.abs(int)
應做下面的Java代碼:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
也就是說,在負的情況下,-x
。
根據JLS section 15.15.4,-x
等於(~x)+1
,其中~
是按位互補運算符。
要檢查這聽起來是否正確,我們以-1爲例。
整數值-1
可以在Java中以十六進制標記爲0xFFFFFFFF
(使用println
或任何其他方法檢查出來)。以-(-1)
因此給出:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
所以,它的工作。
讓我們試用Integer.MIN_VALUE
。明知最低的整數可以通過0x80000000
來表示,即,第一位設置爲1,其餘的31位設置爲0,我們有:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
這就是爲什麼Math.abs(Integer.MIN_VALUE)
回報Integer.MIN_VALUE
。還請注意0x7FFFFFFF
是Integer.MAX_VALUE
。
這就是說,我們如何避免由於這種反直覺的回報值在未來的問題?
我們所能,as pointed out by @Bombe,鑄就我們int
s到long
之前。然而,我們必須要麼
int
s,這並不因爲 Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
工作。long
以某種方式希望我們永遠不會撥打Math.abs(long)
的值等於Long.MIN_VALUE
,因爲我們也有Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
。我們可以用BigInteger
到處都是,因爲BigInteger.abs()
確實總是返回正值。這是一個很好的選擇,比處理原始整數類型要艱難得多。
我們可以寫我們自己的包裝用於Math.abs(int)
,像這樣:
/**
* Fail-fast wrapper for {@link Math#abs(int)}
* @param x
* @return the absolute value of x
* @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
*/
public static int abs(int x) throws ArithmeticException {
if (x == Integer.MIN_VALUE) {
// fail instead of returning Integer.MAX_VALUE
// to prevent the occurrence of incorrect results in later computations
throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
}
return Math.abs(x);
}
int positive = value & Integer.MAX_VALUE
(本質上從Integer.MAX_VALUE
到0
而不是Integer.MIN_VALUE
)作爲最後一點,這個問題似乎已知一段時間了。例如參見this entry about the corresponding findbugs rule。
好吧,不是問題是低估了影響,它可能意味着問題。就個人而言,我寧願有一個異常或數字系統,以更高級別的語言動態增長。 – 2012-12-19 23:47:20