web-dev-qa-db-ja.com

浮動小数点が等しいかどうかをテストします。 (FE_FLOATING_POINT_EQUALITY)

ANTスクリプトでfindbugsを使用していますが、2つのエラーを修正する方法がわかりません。ドキュメントを読みましたが、わかりません。これが私のエラーとそれに伴うコードです:

エラー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インターフェースを実装し、この条件に違反するクラスは、この事実を明確に示す必要があります。推奨される言語は「注:このクラスには、等しいと矛盾する自然順序があります」です。

また、浮動小数点の等式に関するドキュメント

この操作では、2つの浮動小数点値が等しいかどうかを比較します。浮動小数点の計算には丸めが含まれる場合があるため、計算された浮動小数点値と倍精度値は正確でない場合があります。金額などの正確である必要がある値については、BigDecimalなどの固定精度タイプの使用を検討してください。正確である必要のない値については、次のように、ある範囲内で等しいかどうかを比較することを検討してください。if(Math.abs(x --y)<。0000001)。 Java言語仕様、セクション4.2.4を参照してください。

でもわかりません。誰か助けてもらえますか?

20
taraloca

問題1:

FE_FLOATING_POINT_EQUALITYの問題の場合、2つのfloat値を_==_演算子と直接比較しないでください。小さな丸め誤差のため、条件_value1 == value2_であっても、値はアプリケーションにとって意味的に「等しい」可能性があります。当てはまりません。

これを修正するには、次のようにコードを変更します。

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

EPSILONは、コードで定義する必要のある定数であり、アプリケーションに受け入れられる小さな違いを表します。 .0000001。

問題2:

EQ_COMPARETO_USE_OBJECT_EQUALSの問題の場合:x.compareTo(y)がゼロを返す場合は常に、x.equals(y)trueにすることを強くお勧めします。コードでcompareToを実装しましたが、equalsをオーバーライドしていないため、equalsからObjectの実装を継承しています。上記の条件満たされていません。

これを修正するには、クラスでequals(およびおそらくhashCode)をオーバーライドして、x.compareTo(y)が0を返すと、x.equals(y)が返されるようにします。 true

19
Grodriguez

浮動小数点の警告については、浮動小数点はinexactタイプであることに注意してください。これについて与えられた標準的なリファレンス(おそらく一度読む価値があります)は次のとおりです。

すべてのコンピューター科学者が浮動小数点演算について知っておくべきことDavidGoldberg著。

浮動小数点数は正確な値ではないため(小数点以下を数桁に切り上げたときに同じように見えても、わずかに異なる可能性があり、一致しない可能性があります。

Comparable interface は、その実装者による特定の動作を期待しています。警告は、あなたがそれに固執していないことをあなたに伝え、提案された行動を提供しています。

6
martin clayton

私は上記の答えに同意しません。 EqualsとcompareToは、浮動小数点比較でイプシロンを導入するのに間違った場所です。

浮動小数点値は、「==」演算子を使用するだけで、equalsとcompareToによって正確に比較できます。
アプリケーションが計算結果であるfloatを使用している場合、これらの値をイプシロンアプローチと比較する必要があります。これは、これが必要な場所でのみ行う必要があります。たとえば、数学的な線交差法で。
しかし、equalsとcompareToではありません。

この警告は非常に誤解を招く恐れがあります。これは、2つのフロートを比較することを意味します。リートの1つは計算の結果であり、予期しない結果が生じる可能性があります。ただし、多くの場合、このようなフロートは、比較するために、次のような計算の結果ではありません。

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

ここで、fはINVALID_VALUEで初期化され、Javaは常に完全に機能します。ただし、findbugsとsonarcubeは引き続き文句を言います。

したがって、MyPoint2DとMyrectangle2Dの2つのクラスがあると仮定して、findbugsに無視フィルターを追加するだけです。

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