Epsilon assert argümanının anlamıÇift değerler için eşitler


187

assertEqualsÇift değerleri test etmek için junit hakkında bir sorum var . Görebildiğim API belgesini okurken:

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

Kullanımdan kaldırıldı. Bunun yerine assertEquals (çift beklenen, çift gerçek, çift epsilon) kullanın

epsilonDeğer ne anlama geliyor? (Epsilon, Yunan alfabesinde bir harftir, değil mi?).

Birisi bana nasıl kullanılacağını açıklayabilir mi?

Yanıtlar:


198

Epsilon, 2 sayının kapalı olabileceği değerdir. Böylece doğru olduğu süreceMath.abs(expected - actual) < epsilon


3
Peki epsilon olarak hangi değeri geçmeliyim?
emeraldhieu

15
@ Emerald214 hassasiyet miktarı. Çift değerin 0D epsilon olduğunu iddia etmek isterseniz 0 olur (% 100 doğruluk, istisna yok). Eğer bir hata payı istiyorsanız (derece için diyelim) epsilon'u 1 olarak ayarlayabilirsiniz, örneğin 64.2 ° 64.8 ° ile aynıdır (abs (64.8-64.2) <1 olduğundan)
Pieter De Bie

3
Dokümantasyonda "delta - her iki sayının hala eşit kabul edildiği beklenen ve gerçek arasındaki maksimum delta" yazıyor . Bence Yani bu bir olmalıdır <=değil <.
Andrew Cheong

Koda bakarak, doubleIsDifferent(çift değerleri karşılaştırmak için) yöntemi çağırır ve geri döner görüyorum Math.abs(d1 - d2) > delta. Eğer d1 ve d2 arasındaki fark deltadan daha yüksekse, değerler farklıdır ve true değerini döndürür. Değerler eşit kabul edilirse false değerini döndürür. Bu yöntem assertEquals içinde doğrudan çağrılır ve true değerini döndürürse assertEquals çağrılır failNotEqualsve testin sonucu başarısız olur.
anthomaxcool

1
@jbert Birisi sadece bir çok sayının ortalamasını almak veya standart sapmalar yapmakla çalışsaydım tipik bir epsilon çift değerinin ne olacağını önerebilir mi?
simgineer

121

JUnit'in hangi sürümü bu? Ben sadece delta gördüm, epsilon değil - ama bu bir yan sorun!

JUnit javadoc'tan :

delta - her iki sayının hala eşit kabul edildiği beklenen ve gerçek arasındaki maksimum delta.

Muhtemelen aşırıya kaçmış, ama genellikle çok az bir sayı kullanıyorum, örneğin

private static final double DELTA = 1e-15;

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

Eğer kullanıyorsanız hamcrest iddialarını, sadece standardını kullanabilirsiniz equalTo()(bir delta kullanmaz) iki çift kişilik. Ancak bir delta istiyorsanız, closeTo()( javadoc'a bakınız ) kullanabilirsiniz, örn.

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 yaklaşan JUnit 5 , iki katına çıkarken delta'yı isteğe bağlı yapacaktırassertEquals() . Uygulama (eğer ilgileniyorsan) 'dir:

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

57

Kayan nokta hesaplamaları kesin değildir - genellikle yuvarlama hataları ve temsilden kaynaklanan hatalar vardır. (Örneğin, 0.1 tam olarak ikili kayan noktada gösterilemez.)

Bu nedenle, eşitlik için iki kayan nokta değerinin doğrudan karşılaştırılması genellikle iyi bir fikir değildir, çünkü nasıl hesaplandıklarına bağlı olarak küçük bir miktar farklı olabilirler.

"Delta", JUnit javadocs olarak adlandırıldığı gibi, hala eşit olarak kabul edilmeleri için değerlerde tolere edebileceğiniz fark miktarını açıklar. Bu değerin boyutu tamamen karşılaştırdığınız değerlere bağlıdır. Çiftleri karşılaştırırken, genellikle beklenen değerin 10 ^ 6'ya bölünmesini kullanıyorum.


11

Mesele şu ki, kayan nokta sayılarına özgü hassasiyet sorunları nedeniyle iki çift tam olarak eşit olmayabilir. Bu delta değeri ile bir hata faktörüne dayalı olarak eşitlik değerlendirmesini kontrol edebilirsiniz.

Ayrıca bazı kayan nokta değerleri, sonuçları etkileyebilecek NAN ve -Infinity / + Infinity gibi özel değerlere sahip olabilir.

Gerçekten iki katın tam olarak eşit olduğunu karşılaştırmak istiyorsanız, uzun bir temsil olarak karşılaştırmak en iyisidir

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

Veya

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

Bu nüansları dikkate alabilir.

Söz konusu Assert yöntemini araştırmadım, ancak yalnızca önceki türün bu tür sorunlar için kullanımdan kaldırıldığını ve yenisinin bunları dikkate aldığını varsayabilirim.


2

Epsilon, eşit olduğunu düşünerek kabul edebileceğiniz değerler expectedve actualdeğerler arasındaki farktır . .1Örneğin ayarlayabilirsiniz .


2

Matematik yapmıyorsanız, tam kayan nokta değerlerini belirtmenin yanlış bir şey olmadığını unutmayın. Örneğin:

public interface Foo {
    double getDefaultValue();
}

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

Bu durumda, gerçekten MIN_VALUEsıfır olmadığından emin olmak istersiniz ya -MIN_VALUEda MIN_NORMALveya çok küçük bir değerdir. Söyleyebilirsin

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

ancak bu size bir kullanımdan kaldırma uyarısı verir. Bundan kaçınmak için assertEquals(Object, Object)bunun yerine şunları arayabilirsiniz :

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

Ve eğer gerçekten akıllı görünmek istiyorsanız:

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

Ya da sadece Hamcrest'in akıcı tarzı iddialarını kullanabilirsiniz:

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

Değeri Sen kontrol ederse gelmez bazı matematik yapmaktan geliyor olsa da, Epsilon kullanın.


7
Tam olarak eşit olup olmadığını kontrol etmek istiyorsanız, epsilon'u 0,0 olarak ayarlayın - Nesne varyantı gerekli değildir.
Mel Nicholson

-2
Assert.assertTrue(Math.abs(actual-expected) == 0)

Kayan nokta sayıları (şamandıra veya çift) kullanırken, bu güvenilir bir şekilde çalışmaz. Java'daki kayan nokta numaralarının nasıl saklandığını ve aritmetik işlemlerin üzerlerinde nasıl çalıştığını incelemek isteyebilirsiniz. (spoiler: bazı yuvarlama hataları bekliyoruz!)
Attila
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.