对于double值,assertEquals的epsilon参数的含义

elf*_*elf 181 java junit unit-testing

我有一个关于junit assertEquals来测试双值的问题.阅读API文档,我可以看到:

@Deprecated
public static void assertEquals(double expected, double actual)
Run Code Online (Sandbox Code Playgroud)

已过时.使用assertEquals(双重预期,双重实际,双重epsilon)代替

这个epsilon值意味着什么?(Epsilon是希腊字母表中的一封信,对吧?).

有人可以向我解释如何使用它吗?

jbe*_*erg 192

Epsilon是2个数字可以关闭的值.所以它只要声明为真Math.abs(expected - actual) < epsilon

  • @ Emerald214的精确度.如果你想断言双值是0D epsilon将是0(100%准确性,没有例外).如果你想要一个误差范围(例如度数),你可以将epsilon设置为1,这意味着,例如,64.2°与64.8°相同(因为abs(64.8-64.2)<1) (11认同)
  • 那么我应该以epsilon的身份传递什么价值呢? (3认同)
  • 文档说,_"delta - 两个数字仍然被认为是相等的预期和实际之间的最大差值."_所以我认为应该是一个`<=`不是`<`. (2认同)
  • @jbert 如果我只是在处理大量数字的平均值或做标准偏差,有人可以建议典型的 epsilon double 值是多少吗? (2认同)

Jam*_*ett 117

这是哪个版本的JUnit?我只见过delta,而不是epsilon - 但这是一个副作用!

来自JUnit javadoc:

delta - 两个数字仍然被认为相等的预期和实际之间的最大增量.

它可能有点过分,但我通常使用一个非常小的数字,例如

private static final double DELTA = 1e-15;

@Test
public void testDelta(){
    assertEquals(123.456, 123.456, DELTA);
}
Run Code Online (Sandbox Code Playgroud)

如果你正在使用hamcrest断言,你可以使用equalTo()带有两个双精度的标准(它不使用delta).但是,如果你想要一个delta,你可以使用closeTo()(参见javadoc),例如

private static final double DELTA = 1e-15;

@Test
public void testDelta(){
    assertThat(123.456, equalTo(123.456));
    assertThat(123.456, closeTo(123.456, DELTA));
}
Run Code Online (Sandbox Code Playgroud)

仅供参考即将到来的JUnit 5可以assertEquals()使用两个双打时使delta成为可选项.该实施(如果你有兴趣)为:

private static boolean doublesAreEqual(double value1, double value2) {
    return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}
Run Code Online (Sandbox Code Playgroud)


mdm*_*dma 56

浮点计算并不精确 - 通常存在舍入错误和由于表示引起的错误.(例如,0.1不能用二进制浮点精确表示.)

因此,直接比较两个浮点值是否相等通常不是一个好主意,因为它们可能会有少量不同,具体取决于它们的计算方式.

在JUnit javadocs中调用的"delta" 描述了你可以容忍它们仍然被认为是相等的值的差异量.此值的大小完全取决于您要比较的值.比较双打时,我通常使用预期值除以10 ^ 6.


Edw*_*rzo 11

问题是由于浮点数固有的精度问题,两个double可能不完全相等.使用此delta值,您可以根据错误因素控制相等性评估.

此外,某些浮点值可能具有特殊值,如NAN和-Infinity/+ Infinity,它们可能会影响结果.

如果你真的打算比较两个双精度数是完全相等的,那么最好将它们作为长表示法进行比较

Assert.assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(result));
Run Code Online (Sandbox Code Playgroud)

要么

Assert.assertEquals(0, Double.compareTo(expected, result));
Run Code Online (Sandbox Code Playgroud)

这可以考虑这些细微差别.

我没有深入研究过有问题的Assert方法,但我只能假设之前的这种问题已被弃用,新的​​问题确实考虑到了这些问题.