Double.Epsilon para igualdad, mayor que, menor que, menor que o igual a, mayor que o igual a

http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx

Si crea un algoritmo personalizado que determina si dos números de coma flotante pueden considerarse iguales, debe usar un valor que sea mayor que la constante de Epsilon para establecer el margen de diferencia absoluto aceptable para que los dos valores se consideren iguales. (Típicamente, ese margen de diferencia es muchas veces mayor que Epsilon).

Entonces, ¿no es esto realmente un épsilon que podría usarse para las comparaciones? Realmente no entiendo la redacción de MSDN.

¿Se puede usar como épsilon en los ejemplos aquí? – ¿Cuál es la forma más efectiva para la comparación de flotación y doble?

Y, finalmente, esto parece muy importante, por lo que me gustaría asegurarme de tener una implementación sólida para la igualdad, mayor, menor que, menor o igual que, mayor que o igual a.

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 este valor. Mucho más grande.

El tipo System.Double puede representar valores con una precisión de hasta 15 dígitos. Entonces, una estimación simple de primer orden si un valor doble x es igual a una constante es usar 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; } 

Sin embargo, debes tener cuidado, los errores de truncamiento pueden acumularse. Si tanto x como y son valores calculados, entonces debes boost el épsilon.

Me gustaría asegurarme de tener una implementación sólida para igualdad, mayor que, menor que, menor que o igual a, y mayor o igual que.

Está utilizando aritmética binaria en coma flotante.

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

Presumiblemente, entonces está utilizando la aritmética binaria en coma flotante tal como estaba destinada 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.

Como usted es el que proporciona los valores de las cantidades que está manipulando, usted es quien 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, cuando se comparan dos cantidades para la igualdad, la semántica deseada es decir “¿son estas dos cantidades iguales dentro de las barras de error especificadas por cada medición?”

Entonces ahora tenemos una respuesta a tu 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 aquí que sabe cuáles son las tolerancias razonables de los errores, porque usted es la única persona que sabe de dónde provienen las cifras que está manipulando en primer lugar. Use la tolerancia de error que tenga sentido para sus mediciones dada la precisión del equipo que utilizó para producirla.

Si tiene dos valores dobles que son cercanos a 1.0, pero difieren solo en sus bits menos significativos, la diferencia entre ellos será de muchos órdenes de magnitud mayor que Double.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 épsilon personalizado que sea apropiado para el tamaño de las órdenes de magnitud de los valores que se compararán.

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.

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; } 

Se podría usar 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ás usar un número mayor que el double.Epsilon para verificar si dos dobles son aproximadamente iguales.

Por qué el framework .NET no define algo así como

 bool IsApproximatelyEqual(double value, double permittedVariance); 

Está más allá de mí.

Creo que los bits pertinentes en el enlace de MSDN que publicaste son estos:

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

Nota: El valor de la propiedad Epsilon no es equivalente al épsilon de la máquina, que representa el límite superior del error relativo debido al redondeo en la aritmética de coma flotante.

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

Debo 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 cual es bastante sorprendente por decir lo menos.
Quizás alguien más entendido pueda aclarar 🙂

Yo uso el siguiente

 public static class MathUtil { ///  /// smallest such that 1.0+EpsilonF != 1.0 ///  public const float EpsilonF = 1.192092896e-07F; ///  /// smallest such that 1.0+EpsilonD != 1.0 ///  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 quiere verificar la igualdad de dos dobles ‘a’ y ‘b’, puede usar

 (ab).IsZero(); 

y si quiere obtener el resultado de la comparación, use

 (ab).Sign(); 

El problema con la comparación de dobles es que cuando haces 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 épsilon , 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.

Aquí hay algunos códigos que se incluyen dos veces en el Kit 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 usan 1e-6 para épsilon; en otro, usan 1.192093E-07 . Querrá elegir su propio épsilon.

No hay otra opción que tener que calcular 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; }