web-dev-qa-db-ja.com

double値に対するassertEqualsのイプシロン引数の意味

Double値をテストするjunit assertEqualsについて質問があります。私が見ることができるAPIドキュメントを読む:

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

非推奨。代わりにassertEquals(double expected、double actual、double epsilon)を使用してください

epsilon値の意味は何ですか? (イプシロンはギリシャ語のアルファベットの文字ですよね?)。

誰かがそれを使用する方法を説明できますか?

177
elf

イプシロンは、2つの数値がオフになる値です。したがって、Math.abs(expected - actual) < epsilonである限りtrueにアサートされます。

187
jberg

これはJUnitのどのバージョンですか?私はイプシロンではなくデルタを見たことがありますが、それは副次的な問題です!

JUnitから javadoc

delta-両方の数値がまだ等しいと見なされる、期待される値と実際の値の間の最大の差。

おそらくやり過ぎですが、通常は非常に小さな数を使用します。

private static final double DELTA = 1e-15;

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

hamcrest アサーションを使用している場合は、標準のequalTo()を2つのdoubleで使用できます(デルタは使用しません)。ただし、デルタが必要な場合は、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今後の JUnit 5 は、2つのdoubleでassertEquals()を呼び出すときに deltaをオプションにする にもなります。 実装 (興味がある場合):

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

浮動小数点の計算は正確ではありません-多くの場合、丸め誤差と表現による誤差があります。 (たとえば、0.1は2進浮動小数点で正確に表すことはできません。)

このため、2つの浮動小数点値が等しいかどうかを直接比較することは通常、良い方法ではありません。計算方法によってはわずかに異なる場合があるためです。

「デルタ」は、JUnit javadocs で呼ばれるように、値がまだ等しいと見なされるために許容できる差の量を示します。この値のサイズは、比較する値に完全に依存します。 doubleを比較するとき、通常は期待値を10 ^ 6で割った値を使用します。

55
mdma

問題は、浮動小数点数に固有の精度の問題により、2つのdoubleが正確に等しくない場合があることです。このデルタ値を使用すると、エラー要因に基づいて同等性の評価を制御できます。

また、一部の浮動小数点値には、NANや-Infinity/+ Infinityのような特別な値があり、結果に影響を与える可能性があります。

2つのdoubleが正確に等しいことを本当に比較する場合、長い表現として比較するのが最善です。

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

または

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

これらのニュアンスを考慮することができます。

私は問題のAssertメソッドについて詳しく調べていませんが、この種の問題については以前のものが非推奨であり、新しいものはそれらを考慮に入れていると推測できます。

11
Edwin Dalorzo

数学を行わない場合は、正確な浮動小数点値をアサートしても問題はありません。例えば:

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の流fluentなスタイルのアサーションを使用できます。

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

ただし、チェックしている値がdoesである場合は、イプシロンを使用します。

2
David Moles

イプシロンは、expectedactualの値の違いであり、等しいと考えることができます。たとえば、.1を設定できます。

1
Constantiner