it-swarm.com.de

Bedeutung des epsilon-Arguments von assertEquals für doppelte Werte

Ich habe eine Frage zu junit assertEquals, um doppelte Werte zu testen. Beim Lesen des API-Dokuments sehe ich:

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

Veraltet Verwenden Sie stattdessen assertEquals (double expected, double actual, double epsilon)

Was bedeutet der Wert epsilon? (Epsilon ist ein Buchstabe im griechischen Alphabet, oder?).

Kann mir jemand erklären, wie man es benutzt?

181
elf

Epsilon ist der Wert, um den die 2 Zahlen ausgeschaltet sein können. So wird es auf wahr gesetzt, solange Math.abs(expected - actual) < epsilon

191
jberg

Welche Version von JUnit ist das? Ich habe bisher nur Delta gesehen, kein Epsilon - aber das ist ein Nebenproblem!

Von der JUnit javadoc :

delta - das maximale Delta zwischen erwartet und tatsächlich, für das beide Zahlen immer noch als gleich angesehen werden.

Es ist wahrscheinlich übertrieben, aber ich benutze normalerweise eine sehr kleine Zahl, z.

private static final double DELTA = 1e-15;

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

Wenn Sie hamcrest Assertions verwenden, können Sie einfach den Standard equalTo() mit zwei Doubles verwenden (es wird kein Delta verwendet). Wenn Sie jedoch ein Delta wünschen, können Sie einfach closeTo() verwenden (siehe javadoc ), z.

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 das bevorstehende JUnit 5 wird auch Delta optional machen beim Aufruf von assertEquals() mit zwei Doubles. Die Implementierung (wenn Sie interessiert sind) ist:

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

Gleitkommaberechnungen sind nicht genau - es gibt häufig Rundungsfehler und Fehler aufgrund der Darstellung. (Zum Beispiel kann 0.1 im binären Gleitkomma nicht genau dargestellt werden.)

Aus diesem Grund ist der direkte Vergleich zweier Gleitkommawerte auf Gleichheit in der Regel keine gute Idee, da sie je nach Berechnungsmethode geringfügig voneinander abweichen können.

Das "Delta", wie es in der JUnit javadocs genannt wird, beschreibt die Differenz, die Sie in den Werten tolerieren können, damit sie immer noch als gleich gelten. Die Größe dieses Werts hängt vollständig von den Werten ab, die Sie vergleichen. Beim Vergleich von Doppelwerten verwende ich normalerweise den erwarteten Wert geteilt durch 10 ^ 6.

55
mdma

Die Sache ist, dass das Doppelte zwei aufgrund von Genauigkeitsproblemen, die Gleitkommazahlen inhärent sind, möglicherweise nicht genau gleich ist. Mit diesem Deltawert können Sie die Bewertung der Gleichheit anhand eines Fehlerfaktors steuern.

Einige Gleitkommawerte können auch spezielle Werte wie NAN und -Infinity/+ Infinity haben, die die Ergebnisse beeinflussen können.

Wenn Sie wirklich vorhaben, zu vergleichen, dass zwei Doppelsätze genau gleich sind, vergleichen Sie sie am besten als lange Darstellung

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

Oder

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

Was diese Nuancen berücksichtigen kann.

Ich habe mich nicht mit der fraglichen Assert-Methode befasst, kann aber nur davon ausgehen, dass die vorherige für diese Art von Problemen veraltet war und die neue diese berücksichtigt.

11
Edwin Dalorzo

Beachten Sie, dass es nichts Falsches ist, wenn Sie keine mathematischen Berechnungen durchführen. Zum Beispiel:

public interface Foo {
    double getDefaultValue();
}

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

In diesem Fall möchten Sie sicherstellen, dass es wirklich MIN_VALUE Ist, nicht Null oder -MIN_VALUE Oder MIN_NORMAL Oder ein anderer sehr kleiner Wert. Sie können sagen

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

dies führt jedoch zu einer Ablehnungswarnung. Um dies zu vermeiden, können Sie stattdessen assertEquals(Object, Object) aufrufen:

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

Und wenn Sie wirklich schlau aussehen wollen:

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

Oder Sie können einfach fließende Behauptungen von Hamcrest verwenden:

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

Wenn der Wert, den Sie überprüfen, funktioniert aus etwas Mathe stammt, verwenden Sie das Epsilon.

2
David Moles

Epsilon ist ein Unterschied zwischen expected und actual Werten, von denen Sie annehmen können, dass sie gleich sind. Sie können .1 beispielsweise.

1
Constantiner