2011-04-16 14 views
153

Tengo una pregunta sobre junit assertEquals para probar valores dobles. La lectura de la API doc puedo ver:Significado del argumento epsilon de assertEquals para valores dobles

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

desuso. Use assertEquals (doble esperados, dobles simples, dobles épsilon) en lugar

¿Qué significa el valor épsilon? (Epsilon es una letra del alfabeto griego, ¿no?).

¿Alguien puede explicarme cómo usarlo?

Respuesta

168

Epsilon es el valor con el que pueden descontar los 2 números. Por lo tanto, se va a afirmar como verdadera siempre que Math.abs(expected - actual) < epsilon

+1

Entonces, ¿qué valor debo aprobar como épsilon? – Emerald214

+10

@ Emerald214 la cantidad de precisión. Si desea afirmar que un valor doble es 0D epsilon sería 0 (100% de precisión, sin excepciones). Si desea un margen de error (por ejemplo, para grados), puede establecer epsilon en 1, lo que significa que, por ejemplo, 64.2 ° es lo mismo que 64.8 ° (desde abs (64.8-64.2) <1) –

1

Epsilon es una diferencia entre expected y actual valores que puede aceptar pensando que son iguales. Puede establecer .1 por ejemplo.

52

Los cálculos de coma flotante no son exactos; a menudo hay errores de redondeo y errores debido a la representación. (Por ejemplo, 0.1 no se puede representar exactamente en coma flotante binario.)

Debido a esto, la comparación directa de dos valores de coma flotante para la igualdad generalmente no es una buena idea, porque pueden ser diferentes por una pequeña cantidad, dependiendo de cómo fueron calculados

El "delta", como se llama en el JUnit javadocs, describe la cantidad de diferencia que puede tolerar en los valores para que se consideren iguales. El tamaño de este valor depende completamente de los valores que comparas. Al comparar dobles, normalmente utilizo el valor esperado dividido por 10^6.

10

El problema es que dos dobles pueden no ser exactamente iguales debido a problemas de precisión inherentes a los números de coma flotante. Con este valor delta, puede controlar la evaluación de la igualdad en función de un factor de error.

También algunos valores de punto flotante pueden tener valores especiales como NAN y -Infinity/+ Infinity que pueden influir en los resultados.

Si realmente la intención de comparar dos dobles que son exactamente iguales, es mejor Compárelos como una representación a largo

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

O

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

que puede tomar estos matices en cuenta.

No he profundizado en el método Assert en cuestión, pero solo puedo suponer que el anterior fue desaprobado para este tipo de problemas y el nuevo los tiene en cuenta.

96

¿Qué versión de JUnit es esto? Solo he visto delta, no épsilon, ¡pero eso es un problema secundario!

Desde el JUnit javadoc:

delta - delta del máximo entre lo esperado y real para el que ambos números todavía se consideran iguales.

Probablemente sea exagerado, pero normalmente uso un número realmente pequeño, p.

private static final double DELTA = 1e-15; 

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

Si está utilizando hamcrest afirmaciones, sólo puede utilizar el estándar equalTo() con dos dobles (que no utiliza un delta). Sin embargo, si desea un delta, puede usar closeTo() (consulte javadoc), p.

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 la próxima JUnit 5 también make delta optional al llamar assertEquals() con dos dobles. El implementation (si está interesado) es:

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

Tenga en cuenta que si usted no está haciendo matemáticas, no hay nada malo con la afirmación exacta valores de punto flotante. Por ejemplo:

public interface Foo { 
    double getDefaultValue(); 
} 

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

En este caso, usted quiere asegurarse de que es realmente MIN_VALUE, no cero o -MIN_VALUE o MIN_NORMAL o algún otro valor muy pequeño. Puede decir

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

pero esto le dará una advertencia de desaprobación. Para evitar esto, se puede llamar assertEquals(Object, Object) lugar:

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

Y, si realmente quiere mirar inteligente:

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

O simplemente puede usar Hamcrest afirmaciones de estilo fluidez:

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

Si el valor que está comprobando hace proceden de algunos cálculos, utilice el épsilon.

+6

Si desea verificar exactamente igual, configure épsilon a 0.0 - la variante Object no es necesaria. –

Cuestiones relacionadas