[英]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.