繁体   English   中英

对于双值,assertEquals 的 delta 或 epsilon 参数的含义

[英]Meaning of delta or epsilon argument of assertEquals for double values

我有一个关于 JUnit assertEquals来测试double assertEquals值的问题。 阅读API 文档我可以看到:

 @Deprecated public static void assertEquals(double expected, double actual)

已弃用。 使用assertEquals(double expected, double actual, double delta)代替。

(注意:在较旧的文档版本中,delta 参数称为 epsilon)

delta (或epsilon )参数是什么意思?

Epsilon 是两个数字可以关闭的值。 所以只要Math.abs(expected - actual) < epsilon它就会断言为真

这是哪个版本的 JUnit? 我只见过 delta,而不是 epsilon - 但这是一个附带问题!

从 JUnit javadoc

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

这可能有点矫枉过正,但我​​通常使用非常小的数字,例如

private static final double DELTA = 1e-15;

@Test
public void testDelta(){
    assertEquals(123.456, 123.456, DELTA);
}

如果您使用hamcrest断言,您可以只使用标准的equalTo()和两个双打(它不使用增量)。 但是,如果你想要一个增量,你可以使用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));
}

仅供参考,即将推出的JUnit 5还将在使用两个双精度调用assertEquals()使 delta 成为可选 实现(如果您有兴趣)是:

private static boolean doublesAreEqual(double value1, double value2) {
    return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}

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

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

“delta”,正如它在 JUnit javadocs 中所称的那样,描述了您在值中可以容忍的差异量,以便它们仍然被认为是相等的。 此值的大小完全取决于您要比较的值。 比较双打时,我通常使用预期值除以 10^6。

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

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

如果您真的打算比较两个双打完全相等,最好将它们作为长表示进行比较

Assert.assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(result));

或者

Assert.assertEquals(0, Double.compareTo(expected, result));

这可以考虑到这些细微差别。

我没有深入研究有问题的 Assert 方法,但我只能假设以前的方法已被弃用用于此类问题,而新方法确实将它们考虑在内。

请注意,如果您不做数学运算,断言精确的浮点值并没有错。 例如:

public interface Foo {
    double getDefaultValue();
}

public class FooImpl implements Foo {
    public double getDefaultValue() { return Double.MIN_VALUE; }
}

在这种情况下,您要确保它确实是MIN_VALUE ,而不是零或-MIN_VALUEMIN_NORMAL或其他一些非常小的值。 你可以说

double defaultValue = new FooImpl().getDefaultValue();
assertEquals(Double.MIN_VALUE, defaultValue);

但这会给你一个弃用警告。 为避免这种情况,您可以改为调用assertEquals(Object, Object)

// really you just need one cast because of autoboxing, but let's be clear
assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);

而且,如果你真的想看起来很聪明:

assertEquals(
    Double.doubleToLongBits(Double.MIN_VALUE), 
    Double.doubleToLongBits(defaultValue)
);

或者你可以只使用 Hamcrest 流畅风格的断言:

// equivalent to assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
assertThat(defaultValue, is(Double.MIN_VALUE));

但是,如果您检查的值确实来自进行一些数学运算,请使用 epsilon。

Epsilon 是expected值和actual值之间的差异,您可以认为它们相等。 例如,您可以设置.1

我只想提一下很棒的AssertJ库。 这是我去 JUnit 4 和 5 的断言库,也优雅地解决了这个问题:

assertThat(actual).isCloseTo(expectedDouble, within(delta))
Assert.assertTrue(Math.abs(actual-expected) == 0)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM