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

时间:2011-04-16 13:18:23

标签: java unit-testing junit

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

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

已过时。使用assertEquals(double   预期,双重实际,双倍   epsilon)而不是

epsilon值是什么意思? (Epsilon是希腊字母表中的一封信,对吧?)。

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

8 个答案:

答案 0 :(得分:186)

Epsilon是2个数字可以关闭的值。因此,只要Math.abs(expected - actual) < epsilon

,它就会断言为真

答案 1 :(得分:111)

这是哪个版本的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()(它不使用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));
}

仅使用两个双打调用assertEquals()时,即将到来的JUnit 5也将make delta optionalimplementation(如果您感兴趣的话)是:

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

答案 2 :(得分:55)

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

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

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

答案 3 :(得分:11)

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

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

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

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

或者

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

可以考虑这些细微差别。

我没有深入研究过有问题的Assert方法,但我只能假设之前的这类问题已被弃用,而新版本确实考虑了这些问题。

答案 4 :(得分:2)

请注意,如果您没有进行数学运算,那么断言确切的浮点值并没有错。例如:

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。

答案 5 :(得分:1)

Epsilon是expectedactual值之间的差异,您可以接受它们认为它们是平等的。例如,您可以设置.1

答案 6 :(得分:0)

我只想提到很棒的AssertJ库。这是我去JUnit 4和5的断言库的方法,并且还优雅地解决了这个问题:

assertThat(actual).isCloseTo(expectedDouble, within(delta))

答案 7 :(得分:-2)

Assert.assertTrue(Math.abs(actual-expected) == 0)