简体   繁体   English

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

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

I have a question about JUnit assertEquals to test double values.我有一个关于 JUnit assertEquals来测试double assertEquals值的问题。 Reading the API doc I can see:阅读API 文档我可以看到:

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

Deprecated.已弃用。 Use assertEquals(double expected, double actual, double delta) instead.使用assertEquals(double expected, double actual, double delta)代替。

(Note: in older documentation versions, the delta parameter is called epsilon) (注意:在较旧的文档版本中,delta 参数称为 epsilon)

What does the delta (or epsilon ) parameter mean? delta (或epsilon )参数是什么意思?

Epsilon is the value that the 2 numbers can be off by. Epsilon 是两个数字可以关闭的值。 So it will assert to true as long as Math.abs(expected - actual) < epsilon所以只要Math.abs(expected - actual) < epsilon它就会断言为真

Which version of JUnit is this?这是哪个版本的 JUnit? I've only ever seen delta, not epsilon - but that's a side issue!我只见过 delta,而不是 epsilon - 但这是一个附带问题!

From the JUnit javadoc :从 JUnit javadoc

delta - the maximum delta between expected and actual for which both numbers are still considered equal. delta - 两个数字仍被视为相等的预期和实际之间的最大增量。

It's probably overkill, but I typically use a really small number, eg这可能有点矫枉过正,但我​​通常使用非常小的数字,例如

private static final double DELTA = 1e-15;

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

If you're using hamcrest assertions, you can just use the standard equalTo() with two doubles (it doesn't use a delta).如果您使用hamcrest断言,您可以只使用标准的equalTo()和两个双打(它不使用增量)。 However if you want a delta, you can just use closeTo() (see javadoc ), eg但是,如果你想要一个增量,你可以使用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));
}

FYI the upcoming JUnit 5 will also make delta optional when calling assertEquals() with two doubles.仅供参考,即将推出的JUnit 5还将在使用两个双精度调用assertEquals()使 delta 成为可选 The implementation (if you're interested) is: 实现(如果您有兴趣)是:

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

Floating point calculations are not exact - there is often round-off errors, and errors due to representation.浮点计算并不精确 - 通常存在舍入错误,以及由于表示引起的错误。 (For example, 0.1 cannot be exactly represented in binary floating point.) (例如,0.1 不能用二进制浮点精确表示。)

Because of this, directly comparing two floating point values for equality is usually not a good idea, because they can be different by a small amount, depending upon how they were computed.因此,直接比较两个浮点值的相等性通常不是一个好主意,因为它们可能会有少量不同,这取决于它们的计算方式。

The "delta", as it's called in the JUnit javadocs , describes the amount of difference you can tolerate in the values for them to be still considered equal. “delta”,正如它在 JUnit javadocs 中所称的那样,描述了您在值中可以容忍的差异量,以便它们仍然被认为是相等的。 The size of this value is entirely dependent upon the values you're comparing.此值的大小完全取决于您要比较的值。 When comparing doubles, I typically use the expected value divided by 10^6.比较双打时,我通常使用预期值除以 10^6。

The thing is that two double may not be exactly equal due to precision issues inherent to floating point numbers.问题是,由于浮点数固有的精度问题,两个 double 可能不完全相等。 With this delta value you can control the evaluation of equality based on a error factor.使用此 delta 值,您可以控制基于误差因子的相等性评估。

Also some floating-point values can have special values like NAN and -Infinity/+Infinity which can influence results.此外,一些浮点值可能具有特殊值,如 NAN 和 -Infinity/+Infinity,它们会影响结果。

If you really intend to compare that two doubles are exactly equal it is best compare them as an long representation如果您真的打算比较两个双打完全相等,最好将它们作为长表示进行比较

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

Or或者

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

Which can take these nuances into account.这可以考虑到这些细微差别。

I have not delved into the Assert method in question, but I can only assume the previous was deprecated for this kind of issues and the new one does take them into account.我没有深入研究有问题的 Assert 方法,但我只能假设以前的方法已被弃用用于此类问题,而新方法确实将它们考虑在内。

Note that if you're not doing math, there's nothing wrong with asserting exact floating point values.请注意,如果您不做数学运算,断言精确的浮点值并没有错。 For instance:例如:

public interface Foo {
    double getDefaultValue();
}

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

In this case, you want to make sure it's really MIN_VALUE , not zero or -MIN_VALUE or MIN_NORMAL or some other very small value.在这种情况下,您要确保它确实是MIN_VALUE ,而不是零或-MIN_VALUEMIN_NORMAL或其他一些非常小的值。 You can say你可以说

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

but this will get you a deprecation warning.但这会给你一个弃用警告。 To avoid that, you can call assertEquals(Object, Object) instead:为避免这种情况,您可以改为调用assertEquals(Object, Object)

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

And, if you really want to look clever:而且,如果你真的想看起来很聪明:

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

Or you can just use Hamcrest fluent-style assertions:或者你可以只使用 Hamcrest 流畅风格的断言:

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

If the value you're checking does come from doing some math, though, use the epsilon.但是,如果您检查的值确实来自进行一些数学运算,请使用 epsilon。

Epsilon is a difference between expected and actual values which you can accept thinking they are equal. Epsilon 是expected值和actual值之间的差异,您可以认为它们相等。 You can set .1 for example.例如,您可以设置.1

I just want to mention the great AssertJ library.我只想提一下很棒的AssertJ库。 It's my go to assertion library for JUnit 4 and 5 and also solves this problem elegantly:这是我去 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