2010-09-30 122 views
16

我在ANT腳本中使用findbugs,我無法弄清楚如何解決我的兩個錯誤。我已閱讀文檔,但不明白。以下是我的錯誤及其隨附的代碼:測試浮點相等。 (FE_FLOATING_POINT_EQUALITY)

錯誤1:測試浮點相等。 (FE_FLOATING_POINT_EQUALITY)

private boolean equals(final Quantity other) { 
    return this.mAmount == convertedAmount(other); 
} 

錯誤2:EQ_COMPARETO_USE_OBJECT_EQUALS

public final int compareTo(final Object other) { 
    return this.description().compareTo(((Decision) other).description()); 
} 

我讀過的,指出

強烈建議,但沒有嚴格要求的ComparesTo問題的文件( x.compareTo(y)== 0)==(x.equals(y))。一般來說,任何實現了Comparable接口並違反這個條件的類都應該清楚地表明這個事實。推薦的語言是「注意:這個類的自然排序與equals不一致」。

而且對於浮點平等

此操作兩個浮點值是否相等比較文檔。由於浮點計算可能涉及四捨五入,所以計算的浮點數和雙精度值可能不準確。對於必須精確的值(例如貨幣值),請考慮使用固定精度類型,如BigDecimal。對於不需要精確的值,可以考慮在某個範圍內比較相等性,例如:if(Math.abs(x-y)< .0000001)。請參閱Java語言規範,第4.2.4節。

雖然我不明白。任何人都可以幫忙嗎?

回答

15

問題1:

對於FE_FLOATING_POINT_EQUALITY問題,你不應該直接與==操作比較兩個浮點值,因爲由於微小的舍入誤差,該值可能是您的應用程序即使在語義上「平等」條件value1 == value2不適用。

爲了解決這個問題,修改代碼如下:

private boolean equals(final Quantity other) { 
    return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON); 
} 

凡EPSILON是一個常數,你應該在你的代碼中定義,代表小的差異是可以接受您的應用程序,例如0.0000001。

問題2:

對於EQ_COMPARETO_USE_OBJECT_EQUALS問題:強烈建議,凡是x.compareTo(y)返回零,x.equals(y)應該是true。在你的代碼中你已經實現了compareTo,但是你沒有覆蓋equals,所以你從Object繼承了equals的實現,並且不符合上述條件。

爲了在你的類來解決這個問題,覆蓋equals(也許hashCode),這樣當x.compareTo(y)返回0,然後x.equals(y)將返回true

+3

的'equals'方法應該是傳遞(http://javarevisited.blogspot.fr/2011/02/ how-to-write-equals-method-in-java.html)並且與'hashCode'方法一致。請告訴我們關於'equals'實現的更多信息(Math.abs(this.mAmount - convertedAmount(other)) 2013-07-27 18:42:19

+1

@PascalCuoq你解決了這個問題嗎?我可以想到的一種方法是將float轉換爲BigDecimal,並將其轉換爲您需要的精度並計算哈希值。但會有性能影響。 – 2014-07-17 09:34:34

+1

@AlexanderMalakhov我不是問這個問題的人。我只對定義非傳遞式「等號」方法的適當性發表了評論。這裏「解決」沒有問題。浮點值可以被散列,並且可以與Java已經提供的基本運算符進行比較。任何定義非傳遞式「等號」方法的人都會爲自己創造一個問題,解決問題的最簡單方法不是首先創建問題。 – 2014-07-17 09:39:17

6

對於浮點警告,你應該記住浮點數是不精確的類型。對於這個經常給出一個標準的參考(這是值得一讀一次也許)是:

What Every Computer Scientist Should Know About Floating-Point Arithmetic由大衛·戈德堡。

由於浮點數不是精確值 - 即使它們看起來在四捨五入至小數點後也相同 - 它們可能會略有不同,並且無法匹配。

Comparable interface期望其實現者有某種行爲;警告告訴你,你不遵守這一點,並提供建議的行動。

1

我不同意上面的答案。 Equals和compareTo是在浮點比較中引入epsilons的錯誤地方。

只需使用「==」運算符即可通過equals和compareTo精確比較浮點值。
如果您的應用程序使用的漂浮物是計算結果,需要將這些值與epsilon方法進行比較,則應該只在需要此處的位置進行此操作。例如在數學直線交點法中。
但不是在equals和compareTo中。

此警告非常誤導。這意味着比較兩個浮點數,其中一個是計算結果,可能會給出意想不到的結果。 然而,往往這樣的花車,進行比較,是不是一個計算的結果,像

static final double INVALID_VALUE = -99.0; 
if (f == INVALID_VALUE) 

其中f與INVALID_VALUE初始化,將在Java總是完美的工作。 但findbugs和sonarcube仍然會抱怨。

所以只需添加一個忽略過濾器FindBugs的,asuming你有兩個類MyPoint2D和Myrectangle2D

<Match> 
     <OR> 
      <Class name="~.*\.MyPoint2D" /> 
      <Class name="~.*\.MyRectangle2D" /> 
     </OR> 
     <Bug code="FE" /> 
     <Justification author="My Name" /> 
     <Justification 
      text="Floating point equals works (here)." /> 
    </Match> 
+0

使用「無效值」首先不是一種乾淨的方法。但是優化(通常過早地完成)會導致這樣的黑客攻擊,甚至可能是最終的最佳解決方案。從清潔代碼的角度來看,您應該使用一個單獨的字段來存放信息,無論該信息是否有效。那麼你不需要考慮檢查浮動平等。 – Alfe 2016-02-05 12:29:07

+0

我同意,在許多情況下,最好有一個單獨的fiield來顯示有效性。在許多其他情況下不是。 (內部代碼不公開給任何其他類)這裏的主題是與floatin點常量的比較工作 – AlexWien 2016-02-05 15:23:51

+0

內部代碼可能不那麼幹淨的概念是危險的。此外,內部代碼可能需要由必須瞭解代碼的後繼開發人員進行維護。但在某些情況下,我會接受「高度優化」的論點。 – Alfe 2016-02-05 15:27:49