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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3832592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 05:38:30  来源:igfitidea点击:

Test for floating point equality. (FE_FLOATING_POINT_EQUALITY)

javaantfindbugs

提问by taraloca

I am using a findbugs in an ANT script and I can't figure out how to fix two of my errors. I have read the documentation, but don't understand. Here are my errors and the code that goes with them:

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

Error 1: Test for floating point equality. (FE_FLOATING_POINT_EQUALITY)

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

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

Error 2: EQ_COMPARETO_USE_OBJECT_EQUALS

错误 2:EQ_COMPARETO_USE_OBJECT_EQUALS

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

I've read the documentation for the ComparesTo issue that states

我已经阅读了说明的 ComparesTo 问题的文档

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."

强烈推荐,但不严格要求 (x.compareTo(y)==0) == (x.equals(y))。一般来说,任何实现 Comparable 接口并违反此条件的类都应该清楚地表明这一事实。推荐的语言是“注意:这个类有一个与 equals 不一致的自然顺序。”

and also the docs regarding the floating point equality

以及有关浮点相等性的文档

This operation compares two floating point values for equality. Because floating point calculations may involve rounding, calculated float and double values may not be accurate. For values that must be precise, such as monetary values, consider using a fixed-precision type such as BigDecimal. For values that need not be precise, consider comparing for equality within some range, for example: if ( Math.abs(x - y) < .0000001 ). See the Java Language Specification, section 4.2.4.

此操作比较两个浮点值是否相等。由于浮点计算可能涉及四舍五入,因此计算出的浮点和双精度值可能不准确。对于必须精确的值(例如货币值),请考虑使用固定精度类型,例如 BigDecimal。对于不需要精确的值,请考虑比较某个范围内的相等性,例如: if ( Math.abs(x - y) < .0000001 )。请参阅 Java 语言规范,第 4.2.4 节。

I don't get it though. Can anyone please help?

我不明白。有人可以帮忙吗?

采纳答案by Grodriguez

Problem 1:

问题1:

For the FE_FLOATING_POINT_EQUALITY issue, you should not be comparing two float values directly with the ==operator, since due to tiny rounding errors, the values might be semantically "equal" for your application even if the condition value1 == value2does not hold true.

对于 FE_FLOATING_POINT_EQUALITY 问题,您不应直接使用==运算符比较两个浮点值,因为由于舍入误差很小,即使条件value1 == value2不成立,这些值对于您的应用程序来说也可能在语义上“相等” 。

In order to fix this, modify your code as follows:

为了解决这个问题,修改你的代码如下:

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

Where EPSILON is a constant that you should define in your code, and represents small differences that are acceptable to your application, e.g. .0000001.

其中 EPSILON 是您应该在代码中定义的常量,代表您的应用程序可接受的微小差异,例如 .0000001。

Problem 2:

问题2:

For the EQ_COMPARETO_USE_OBJECT_EQUALS issue: It is strongly recommended that wherever x.compareTo(y)returns zero, x.equals(y)should be true. In your code you have implemented compareTo, but you have not overriden equals, so you are inheriting the implementation of equalsfrom Object, and the above condition is not met.

对于 EQ_COMPARETO_USE_OBJECT_EQUALS 问题:强烈建议无论在哪里x.compareTo(y)返回零,x.equals(y)都应该是true. 在你的代码中你已经实现了compareTo,但是你没有重写equals,所以你是继承了equalsfrom的实现,Object不满足上面的条件。

In order to fix this, override equals(and perhaps hashCode) in your class, so that when x.compareTo(y)returns 0, then x.equals(y)will return true.

为了解决这个问题,在您的班级中覆盖equals(可能还有hashCode),以便当x.compareTo(y)返回 0 时,x.equals(y)将返回true.

回答by martin clayton

For the floating point warning, you should bear in mind that floats are an inexacttype. A standard reference oft given for this (which is worth reading once perhaps) is:

对于浮点警告,您应该记住浮点数是一种不精确的类型。经常为此给出的标准参考(也许值得一读)是:

What Every Computer Scientist Should Know About Floating-Point Arithmeticby David Goldberg.

大卫·戈德堡 (David Goldberg) 的《每个计算机科学家都应该了解的关于浮点运算的知识》。

Because floats are not exact values - even if they lookthe same when rounded up to a few decimals - they can differ very slightly, and fail to match.

因为浮点数不是精确的值 - 即使它们在四舍五入后看起来相同 - 它们可能会略有不同,并且无法匹配。

The Comparable interfaceexpects a certain behaviour by its implementor; the warning is telling you you are not adhering to that, and offering suggested actions.

可比的界面预计在其执行者一定的行为; 警告是告诉你你没有遵守这一点,并提供建议的行动。

回答by AlexWien

I do not agree with the answers above. Equals and compareTo are the wrong place to introduce epsilons in floating point comparisons.

我不同意上面的答案。Equals 和 compareTo 是在浮点比较中引入 epsilon 的错误位置。

Floating point values can be compared exactly by equals and compareTo, just using the "==" operator.
If your application, uses floats that are a result of calculation, need to compare these values with the epsilon approach, it should do that only in that place where this is needed. E.g in a mathematical line intersection method.
But not in equals and compareTo.

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

This warning is very misleading. It means comparing two floats where at leats one is a result of an calculation might give unexpected result. However, often such floats, to compare, are not a result of a calculation, like

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

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

where f is initialized with INVALID_VALUE, will in java always work perfectly. But findbugs and sonarcube will still complain.

其中 f 用 INVALID_VALUE 初始化,在 java 中总是可以完美工作。但是 findbugs 和 sonarcube 仍然会抱怨。

So just add an ignore filter to findbugs, asuming you have two classes MyPoint2D and Myrectangle2D

所以只需添加一个忽略过滤器来查找错误,假设您有两个类 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>