Java Float.compare()是否总是产生正确的结果



这似乎是一个我很容易找到答案的问题,但我看不到任何关于这个问题的条目。我知道浮点运算是如何工作的,为了比较浮点数,我需要使用epsilon检查。当我和我的团队分享这件事时,我的一位同事问我这个问题,我无法回答。

Java上的比较方法是否总是产生正确的结果,即f1f2的ε检查将产生的结果?

Float.compare(float f1, float f2);

注意:特别要考虑平等情况下的这个问题。

不,Float.compare不使用任何类型的epsilon检查。

以下是OpenJDK 13方法的实现示例:

/**
* Compares the two specified {@code float} values. The sign
* of the integer value returned is the same as that of the
* integer that would be returned by the call:
* <pre>
*    new Float(f1).compareTo(new Float(f2))
* </pre>
*
* @param   f1        the first {@code float} to compare.
* @param   f2        the second {@code float} to compare.
* @return  the value {@code 0} if {@code f1} is
*          numerically equal to {@code f2}; a value less than
*          {@code 0} if {@code f1} is numerically less than
*          {@code f2}; and a value greater than {@code 0}
*          if {@code f1} is numerically greater than
*          {@code f2}.
* @since 1.4
*/
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1;           // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1;            // Neither val is NaN, thisVal is larger
// Cannot use floatToRawIntBits because of possibility of NaNs.
int thisBits    = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ?  0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1));                          // (0.0, -0.0) or (NaN, !NaN)
}

来源

如果你阅读Float.compare()的Javadoc,他们会谈论"数字相等"。这意味着表示相同理论数,但编码不同的值被认为是相等的。例如0.0 == -0.0和次正规数。

Epsilon检查(检查两个数字是否在彼此的范围内,通常是一个非常小的数字(并不是一个事实上的标准,而且有很多实际问题(比如当你不知道数字的大小时,该选择哪个Epsilon,或者当两个数字的大小大不相同时该怎么办(。由于这个原因,Java只实现精确的操作。

否,java.lang.Float.compare(double,double(对于彼此隐藏的epsilon值内的值不返回0(相等(。

然而,您可以很容易地手动进行这样的比较,或者使用几个常见库中的一个库进行比较。

手动您可以编写一个函数,如果相等的模糊检查通过,则返回零,否则返回Float.compare((。相等的模糊检测可以类似于Math.abs( f1 - f2 ) < epsilon

或者,在Apache Commons Math中,Precision类为接受epsilon值的浮点和双精度提供compares((和equals((方法。该类以常数epsilon提供epsilon的值。

或者,在Google Guava中,DoubleMath类提供fuzzyCompare((和fuzzyEquals((方法,它们接受doubles和epsilon值。

听起来你需要检查两个浮点值在给定的非负增量内是否相等,对吗?

您可以使用JUnit的Assertions.assertEquals((方法来实现这一点:

assertEquals​(float f1, float f2, float delta)

通常使用以下测试完成:if (abs(a-b) < DELTA)。。。其中DELTA被全局声明为一些非常小的数值常数,以确保整个程序的一致性。由于测试非常简单,我喜欢明确地说明它

最新更新