簡體   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