2010-03-09 31 views
45

http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspxDouble.Epsilon por la igualdad, mayor que, menor que, menor que o igual a, mayor que o igual a

Si crea un algoritmo personalizado que Determina si dos de punto flotante números pueden se considere igual, debe usar un valor que sea mayor que la constante de Epsilon para establecer el margen absoluto aceptable de diferencia para los dos valores que son considerados iguales. (Por lo general, que margen de diferencia es muchas veces mayor que Epsilon.)

Así es que esto no es realmente un épsilon que podría ser utilizado para las comparaciones? Realmente no entiendo la redacción de MSDN.

¿Se puede utilizar como épsilon en los ejemplos aquí? - What is the most effective way for float and double comparison?

Y finalmente esto parece muy importante así que me gustaría para asegurarse de que tengo una aplicación sólida para la igualdad, mayor que, menor que, menor que o igual a, y mayor o igual a.

Respuesta

66

No sé lo que estaban fumando cuando escribieron eso. Double.Epsilon es el valor de punto flotante no denormal representable más pequeño que no es 0. Todo lo que sabe es que, si hay un error de truncamiento, siempre será mayor que que este valor. Mucho más grande.

El tipo System.Double puede representar valores con una precisión de hasta 15 dígitos. Así que un simple primera estimación orden si un valor doble x es igual a una constante es utilizar un épsilon de constante * 1E-15

public static bool AboutEqual(double x, double y) { 
    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15; 
    return Math.Abs(x - y) <= epsilon; 
} 

Usted tiene que mirar hacia fuera sin embargo, los errores de truncamiento se pueden acumular. Si ambos x y y son valores calculados, entonces tiene que aumentar el épsilon.

+8

Microsoft dice 'Representa el valor doble positivo más pequeño que es mayor que cero. Consulte http://msdn.microsoft.com/en-us/library/system.double.epsilon%28v=vs.110%29.aspx. –

+1

@Ian Eso es lo que 'Double.Epsilon' debería ser, pero david.pfx lo define tal como es :-( –

+0

1.0 + double.Epsilon = 1.0 –

4

Podría utilizarse para realizar comparaciones, suponiendo que desea asegurarse de que los dos valores sean exactamente iguales o que tengan la menor diferencia representable para el tipo doble. En general, querrá usar un número mayor que double.Epsilon para verificar si dos dobles son aproximadamente iguales.

Por qué el marco .NET no define algo como

bool IsApproximatelyEqual(double value, double permittedVariance); 

está más allá de mí.

3

creo que los bits correspondientes en el enlace de MSDN informados son los siguientes:

Sin embargo, la propiedad Epsilon no es una medida general de precisión de la tipo doble; se aplica solo a instancias dobles que tienen un valor de cero.

Nota: El valor de la propiedad Epsilon no es equivalente a la máquina epsilon, que representa la parte superior unido del error relativo debido a redondeo en aritmética de punto flotante.

Este valor no se define como más pequeño positivo número x, tal que x + 1.0 no es igual a 1,0, por lo Double.Epsilon no se puede utilizar para "casi igualdad". No existe una constante en el marco cuyo valor sea el más pequeño número positivo x, de modo que x + 1.0 no es igual a 1.0.

Tengo que decir que eso me sorprende. Yo también había supuesto que Double.Epsilon era el equivalente de DBL_EPSILON en c/C++, ¡claramente no!

Por lo que puedo leer acerca de ese enlace, parece estar diciendo 'necesitas encontrar un valor decente para las comparaciones', lo que es bastante sorprendente por decir lo menos.
Tal vez alguien más conocedor pueden aclarar :)

9

Si tiene dos valores dobles que están cerca de 1.0, pero difieren en sólo sus bits menos significativos, entonces la diferencia entre ellas será en muchos órdenes de magnitud mayor que el doble .Epsilon. De hecho, la diferencia es 324 órdenes de magnitud decimales. Esto se debe al efecto de la porción del exponente. Double.Epsilon tiene un gran exponente negativo, mientras que 1.0 tiene un exponente de cero (después de eliminar los sesgos, por supuesto).

Si desea comparar dos valores similares para la igualdad, deberá elegir un valor de épsilon personalizado que sea apropiado para el tamaño de las órdenes de magnitud de los valores que se van a comparar.

Si los valores dobles que está comparando están cerca de 1.0. Entonces el valor del bit menos significativo estaría cerca de 0.0000000000000001. Si los valores dobles que está comparando están en los cuatrillones, entonces el valor del bit menos significativo podría ser de hasta mil. No se puede usar ningún valor único para épsilon para las comparaciones de igualdad en ambas circunstancias.

1

El problema con la comparación de dobles es que cuando se hace una comparación entre dos resultados matemáticos diferentes que son iguales pero que, debido a errores de redondeo, no se evalúan con el mismo valor, tendrán alguna diferencia ... que es más grande que epsilon, excepto en casos extremos. Y usar un valor épsilon confiable también es difícil. Algunas personas consideran que dos dobles son iguales si la diferencia entre ellos es menor que algún valor porcentual, ya que el uso de una diferencia mínima estática épsilon puede significar que sus diferencias son demasiado pequeñas o grandes cuando el doble en sí mismo es alto o bajo.

39

me gustaría asegurarme de que tengo una aplicación sólida para la igualdad, mayor que, menor que, menor que o igual a, y mayor o igual a.

Está utilizando la aritmética de punto flotante binario.

La aritmética binaria en coma flotante se diseñó para representar cantidades físicas como longitud, masa, carga, tiempo, etc.

Presumiblemente, entonces está utilizando una aritmética binaria en coma flotante como estaba destinado a ser utilizada: para hacer cálculos aritméticos en cantidades físicas.

Las mediciones de cantidades físicas siempre tienen una precisión particular, dependiendo de la precisión del dispositivo utilizado para medirlas.

Dado que usted es el que proporciona los valores de las cantidades que está manipulando, usted es el que sabe cuáles son las "barras de error" en esa cantidad. Por ejemplo, si proporciona la cantidad "la altura del edificio es de 123.56 metros", entonces sabe que esto es exacto al centímetro, pero no al micrómetro.

Por lo tanto, al comparar dos cantidades para igualdad, la semántica deseada es decir "¿son estas dos cantidades iguales dentro de las barras de error especificadas por cada medición?"

Así que ahora tenemos una respuesta a su pregunta. Lo que debe hacer es realizar un seguimiento de cuál es el error en cada cantidad; por ejemplo, la altura del edificio es "dentro de 0.01 de 123.56 metros" porque sabes que así es la precisión de la medición. Si luego obtiene otra medición que es 123.5587 y desea saber si las dos medidas son "iguales" dentro de las tolerancias de error, haga la resta y vea si cae en la tolerancia de error. En este caso, sí. Si las mediciones fueron de hecho precisas para el micrometre, entonces no son iguales.

En resumen: usted es la única persona que sabe lo tolerancias de error son sensibles, porque usted es la única persona que sabe dónde están las figuras está manipulando vinieron de en el primer lugar. Use la tolerancia de error que tenga sentido para sus mediciones dada la precisión del equipo que utilizó para producirla.

+2

Aunque es cierto que es correcto señalar que la tolerancia es una medida más práctica y directa para definir que estaba investigando las inexactitudes de la representación codificada como regla de primer paso general y que la tolerancia sería un segundo pase opcional dependiendo de la situación específica. – ss2k

+1

Eric, si creas algún tipo de estructura de datos (por ejemplo, para el juego) y quieres permitir que otros juegos lo usen, todos tendrán diferente tolerancia ya que todos usan diferentes sistemas de coordenadas. Entonces, decidir cuál será tu épsilon no es solo una cuestión de condiciones personales, creo. – Tom

+2

No respondió la pregunta. No es una cuestión de gusto o contexto, se relaciona con la definición de un doble en la memoria (IEEE 754). –

0

Aquí hay un código que incluía dos veces en el Juego de Herramientas de Control de Silverlight:

public static bool AreClose(double value1, double value2) 
    { 
     //in case they are Infinities (then epsilon check does not work) 
     if(value1 == value2) return true; 
     // This computes (|value1-value2|/(|value1| + |value2| + 10.0)) < DBL_EPSILON 
     double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; 
     double delta = value1 - value2; 
     return(-eps < delta) && (eps > delta); 
    } 

En un lugar que utilizan para 1e-6 épsilon; en otro usan 1.192093E-07. Querrá elegir su propio épsilon.

+0

Este parece prometedor. Parece que solucionan el problema de la disminución de la precisión decimal al comparar valores altos. Por supuesto, debe considerar si desea este tipo de escalado de precisión. Es tan aplicable como la versión con epsilon estático. –

5

Acabo de hacer esto - usando la idea de Kent Bogarts.

private bool IsApproximatelyEqual(double x, double y, double acceptableVariance) 
{ 
    double variance = x > y ? x - y : y - x; 
    return variance < acceptableVariance; 

    //or 
    //return Math.Abs(x - y) < acceptableVariance; 
} 
0

No hay ninguna opción que tenga que calcularlo usted mismo o definir la propia constante.

double calculateMachineEpsilon() { 
    double result = 1.0; 
    double one = 1.0/256; 

    while(one + result/2.0 != 1.0) { 
     result/=2.0; 
    } 
    return result; 
} 
0

utilizo el siguiente

public static class MathUtil { 
    /// <summary> 
    /// smallest such that 1.0+EpsilonF != 1.0 
    /// </summary> 
    public const float EpsilonF = 1.192092896e-07F; 

    /// <summary> 
    /// smallest such that 1.0+EpsilonD != 1.0 
    /// </summary> 
    public const double EpsilonD = 2.2204460492503131e-016; 

    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static bool IsZero(this double value) { 
     return value < EpsilonD && value > -EpsilonD; 
    } 

    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static int Sign(this double value) { 
     if (value < -EpsilonD) { 
      return -1; 
     } 
     if (value > EpsilonD) 
      return 1; 
     return 0; 
    } 

y si desea comprobar la igualdad de dos dobles 'a' y 'b', puede utilizar

(a-b).IsZero(); 

y si desea obtener el resultado de comparación, use

(a-b).Sign(); 
Cuestiones relacionadas