Java 浮点相等性测试。(浮点相等)

Java 浮点相等性测试。(浮点相等),java,ant,findbugs,Java,Ant,Findbugs,我在ANT脚本中使用findbugs,我不知道如何修复我的两个错误。我已经阅读了文档,但不理解。以下是我的错误及其代码: 错误1:测试浮点相等性。(浮点相等) 错误2:EQ\u比较使用对象等于 public final int compareTo(final Object other) { return this.description().compareTo(((Decision) other).description()); } 我已经阅读了有关ComparesTo问题的文档,其中

我在ANT脚本中使用findbugs,我不知道如何修复我的两个错误。我已经阅读了文档,但不理解。以下是我的错误及其代码:

错误1:测试浮点相等性。(浮点相等)

错误2:EQ\u比较使用对象等于

public final int compareTo(final Object other) {
    return this.description().compareTo(((Decision) other).description());
}
我已经阅读了有关ComparesTo问题的文档,其中指出

强烈建议(x.compareTo(y)==0)=(x.equals(y)),但不是严格要求。一般来说,任何实现可比较接口并违反此条件的类都应该清楚地指出这一事实。建议使用的语言是“注意:此类具有与equals不一致的自然顺序。”

还有关于浮点等式的文档

此操作比较两个浮点值是否相等。由于浮点计算可能涉及舍入,因此计算出的浮点值和双精度值可能不准确。对于必须精确的值,例如货币值,考虑使用固定精度类型,如BigDecimal。对于不需要精确的值,考虑在一定范围内比较相等性,例如:(数学。ABS(X-Y)<000000。1)。请参阅Java语言规范,第4.2.4节


但我不明白。有人能帮忙吗?

关于浮点警告,请记住浮点是一种不精确的类型。对此经常给出的标准参考(或许值得一读)是:

大卫·戈德伯格

因为浮点数不是精确的值——即使它们在四舍五入到几位小数时看起来是一样的——它们可能相差很小,并且无法匹配

预期其实施者的某种行为;警告是告诉您您没有遵守,并提供建议的操作。

问题1:

对于FE_浮点_相等问题,不应直接使用
=
运算符比较两个浮点值,因为由于存在微小的舍入错误,即使条件
value1==value2
不成立,这些值在语义上也可能“相等”

要解决此问题,请按如下方式修改代码:

private boolean equals(final Quantity other) {
    return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON);
}
private boolean equals(最终数量其他){
返回值(Math.abs(this.mAmount-convertedAmount(other))
其中EPSILON是您应该在代码中定义的常量,表示应用程序可以接受的小差异,例如..0000001

问题2:

对于EQ\u COMPARETO\u USE\u OBJECT\u EQUALS问题:强烈建议在
x.COMPARETO(y)
返回零的地方,
x.EQUALS(y)
应为
true
。在您的代码中,您已经实现了
compareTo
,但是您没有覆盖
equals
,因此您从
对象继承了
equals
的实现,并且不满足上述条件


为了解决这个问题,在你的类中重写
equals
(也许还有
hashCode
),这样当
x.compareTo(y)
返回0时,
x.equals(y)
将返回
true
我不同意上面的答案。 Equals和compareTo是在浮点比较中引入ε的错误位置

浮点值可以通过equals和compareTo进行精确比较,只需使用“==”运算符即可。
如果您的应用程序使用的浮点值是计算结果,需要将这些值与epsilon方法进行比较,则应仅在需要的地方进行比较。例如,在数学直线相交法中。
但不是在平等和比较中

这一警告具有误导性。这意味着比较两个浮动,其中至少有一个是计算的结果,可能会产生意外的结果。 然而,相比之下,这种浮动通常不是计算的结果,比如

static final double INVALID_VALUE = -99.0;
if (f == INVALID_VALUE)
其中f是用无效的_值初始化的,在java中,它将始终完美地工作。 但是findbugs和sonarcube仍然会抱怨

因此,只需向findbugs添加一个忽略过滤器,因为您有两个类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>


equals
方法应该是可传递的(),并且与
hashCode
方法一致。请告诉我们有关您的
equals
实现的更多信息,如
(Math.abs(this.mAmount-convertedAmount(other))
,以及它如何满足这些要求。@PascalCuoq您解决了这个问题吗?我能想到的一种方法是将float转换为BigDecimal,将四舍五入转换为所需的精度,然后计算哈希值。但这会对性能产生影响。@AlexanderMalakhov我不是问这个问题的人。我只是对定义一个非传递的
equals
方法的适当性发表了评论。这里没有“解决”的问题。浮点值可以散列,并且可以与Java已经提供的基本运算符进行相等性比较。任何定义了不可传递的
equals
方法的人都是在为自己制造问题,解决问题的最简单方法就是一开始就不创建它。@PascalCuoq。我所说的“解决”的意思正是——使
等于
可传递的,并且与
hashCode
同步。我的建议解决了
hashCode
(仅在该方法中转换为BigDecimal),但不等于
。作为数学家,这让我有点紧张:)(供参考)哦,等等。这也适用于
等于
。在比较之前,应四舍五入至所需精度,并比较四舍五入值。不过,性能可能仍然是一个问题。首先,使用“无效值”并不是一个干净的方法。但是优化(通常过早地完成)可能会导致这样的攻击
<Match>
        <OR>
            <Class name="~.*\.MyPoint2D" />
            <Class name="~.*\.MyRectangle2D" />
        </OR>
        <Bug code="FE" />
        <Justification author="My Name" />
        <Justification
            text="Floating point equals works (here)." />
    </Match>