![](/img/trans.png)
[英]How to call assertEquals with Double Epsilon/Precision in Kotlin?
[英]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_VALUE
或MIN_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.