2011-03-26 48 views

回答

72

Integer.MIN_VALUE-2147483648,但32位整數可以包含的最大值是+2147483647。嘗試在32位int中表示+2147483648將有效「翻轉」至-2147483648。這是因爲,當使用有符號整數時,+2147483648-2147483648的二進制補碼二進制表示是相同的。但這不是問題,因爲+2147483648被認爲超出範圍。

想了解更多有關此事的信息,您可能需要查看Wikipedia article on Two's complement

+3

好吧,不是問題是低估了影響,它可能意味着問題。就個人而言,我寧願有一個異常或數字系統,以更高級別的語言動態增長。 – 2012-12-19 23:47:20

11

以下是Java的醫生說了Math.abs()在javadoc

注意,如果參數等於 Integer.MIN_VALUE值的,在 表示的最小負int值, 結果是相同的值,其中 是負值。

0

2147483648在java中不能存儲爲整數,其二進制表示與-2147483648相同。

0

(int) 2147483648L == -2147483648有一個負數沒有正的等值,所以沒有正值。您將看到與Long.MAX_VALUE相同的行爲。

1

一看就知道你期待,投Integer.MIN_VALUElong結果:

System.out.println(Math.abs((long) Integer.MIN_VALUE)); 
+1

確實有可能的修復!然而,這並沒有解決'Math.abs'通過返回一個負數來違反直覺的事實:'Math.abs(Long.MIN_VALUE)== Long.MIN_VALUE' – 2013-06-17 09:38:42

+0

@bernardpaulus,那麼,它應該做什麼,除了拋出'ArithmeticException'?此外,該行爲在API文檔中有明確記錄。 – Bombe 2013-06-21 08:39:11

+0

有沒有很好的答案給你的問題...我只想指出,這種行爲是bug的一個來源,並不是通過使用'Math.abs(long)'來解決的。我在這裏對我的錯誤表示歉意:我認爲你提出使用'Math.abs(long)'作爲解決方法,當你將它展示爲一種簡單的方法來「查看提交者期望的結果」。抱歉。 – 2013-06-22 23:19:35

27

你指出的行爲的確,反直覺的。但是,此行爲是由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。還請注意0x7FFFFFFFInteger.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); 
} 
  • 使用整數位與清除高比特,確保結果是非-negative:int positive = value & Integer.MAX_VALUE(本質上從Integer.MAX_VALUE0而不是Integer.MIN_VALUE

作爲最後一點,這個問題似乎已知一段時間了。例如參見this entry about the corresponding findbugs rule

相關問題