2012-03-23 71 views
5

Al comparar dobles para la igualdad, tenemos que dar un nivel de tolerancia, porque el cálculo de coma flotante podría introducir errores. Por ejemplo:comparación de punto flotante de asignación constante

double x; 
double y; 
x = f(); 
y = g(); 

if (fabs(x-y)<epsilon) { 
    // they are equal! 
} else { 
    // they are not! 
} 

Sin embargo, si simplemente asigno un valor constante, sin ningún tipo de cálculo, ¿sigue siendo necesario para comprobar la épsilon?

double x = 1; 
double y = 1; 

if (x==y) { 
    // they are equal! 
} else { 
    // no they are not! 
} 

¿Es == comparación lo suficientemente bueno? O tengo que hacer fabs(x-y)<epsilon otra vez? ¿Es posible introducir un error en la asignación? ¿Soy demasiado paranoico?

¿Qué hay de fundición (double x = static_cast<double>(100))? ¿Va a introducir también un error de coma flotante?

estoy usando C++ en Linux, pero si se diferencia por el idioma, me gustaría entender que también.

+0

Si necesita un epsilon depende de la situación. P.ej. cuando necesitas una igualdad transitiva ('a == b && b == c' implica' a == c'), entonces no puedes usar un épsilon. Por cierto, 'doble x = 1' ya significa 'doble x = static_cast (1)' – MSalters

Respuesta

3

En realidad, depende del valor y de la aplicación. estándar de C++ (proyecto n3126) tiene esto que decir en 2.14.4 Floating literals:

Si el valor escalado está en el rango de los valores representables para su tipo, el resultado es el valor escalado si representable, de lo contrario el representable más grande o más pequeña valor más cercano al valor escalado, elegido de una manera definida por la implementación.

En otras palabras, si el valor es exactamente representable (y 1 Es decir, en IEEE754, como es 100 en su vaciado estático), se obtiene el valor. De lo contrario (como con 0.1) se obtiene una coincidencia cercana definida por la implementación (a). Ahora estaría muy preocupado por una implementación que eligió un diferente partido cerrado basado en la misma entrada de señal pero es posible.


(a) En realidad, ese párrafo se puede leer de dos maneras, o bien la aplicación es libre de elegir entre el menor valor superior más próximo o cercano, independientemente de que en realidad es el más cercano, o se debe elegir lo más cercano al valor deseado.

Si este último, no cambia esta respuesta, sin embargo, ya que todo lo que tiene que hacer es codificar un punto flotante exactamente en el punto medio de dos tipos representables y la implementación es una vez más libre de elegir.

Por ejemplo, se puede alternar entre el superior más próximo y el siguiente más baja para redondear el mismo motivo del banquero se aplica - para reducir los errores acumulativos.

+0

Algunas implementaciones parecen evaluar 'literales float' encontrando el valor' double' más cercana a un 'float', y después de que el redondeo a una 'flotar'. Esto a veces puede causar literales 'float' cuyo valor real es ligeramente superior o inferior a un' double' que se encuentra exactamente entre dos valores 'float' adyacentes a los que se les asignará un valor que no es el más cercano. – supercat

0

No se si asigna literales que deben ser los mismos :)

Además, si comienza con el mismo valor y hacer las mismas operaciones, que deben ser los mismos.

valores de coma flotante no son exactos, pero las operaciones deben producir resultados consistentes :)

0

Ambos casos son en última instancia, sujeta a las representaciones de ejecución definido.

almacenamiento de valores de punto flotante y sus representaciones adquieren formas Mayo - carga por dirección o constante? optimizado por matemáticas rápidas? ¿Cuál es el ancho de registro? ¿está almacenado en un registro SSE? Existen muchas variaciones.

Si necesitas comportamiento preciso y portabilidad, no dependen de este comportamiento definido por la implementación.

0

IEEE-754, que es una implementación estándar común de los números de coma flotante, requiere operaciones de coma flotante para producir un resultado que es el valor representable más cercano a un resultado infinitamente preciso. Por lo tanto, la única imprecisión que enfrentará es el redondeo después de cada operación que realice, así como la propagación de errores de redondeo de las operaciones realizadas anteriormente en la cadena. Los flotadores no son per se inexactos. Y por cierto, epsilon puede y debe ser calculado, puede consultar cualquier libro numérico sobre eso.

números de punto flotante pueden representar números enteros con precisión hasta la longitud de su mantisa. Así que, por ejemplo, si transfiere de un int a un doble, siempre será exacto, pero para convertirlo en un flotante, ya no será exacto para enteros muy grandes.

Hay un ejemplo importante de uso extenso de números de coma flotante como sustituto de enteros, es el lenguaje de scripts LUA, que no tiene un tipo entero incorporado, y los números de coma flotante se usan ampliamente para control de flujo y lógica etc. La penalización de rendimiento y almacenamiento al usar números de punto flotante resulta ser más pequeña que la penalización de resolver múltiples tipos en tiempo de ejecución y hace que la implementación sea más ligera. LUA ha sido ampliamente utilizado no solo en PC, sino también en consolas de juegos.

Ahora, muchos compiladores tienen un modificador opcional que deshabilita la compatibilidad IEEE-754. Luego se hacen compromisos. Los números desnormalizados (números muy muy pequeños donde el exponente ha alcanzado el menor valor posible) a menudo se tratan como cero, y se pueden realizar aproximaciones en la implementación de potencia, logaritmo, sqrt y 1/(x^2), pero suma/resta, la comparación y la multiplicación deben conservar sus propiedades para los números que se pueden representar exactamente.

0

La respuesta fácil: Para constantes == está bien. Hay dos excepciones que se debe tener en cuenta:

Primera excepción:

== 0.0 -0.0

Hay un cero negativo que compara la igualdad para el estándar IEEE 754. Esto significa 1/INFINITY == 1/-INFINITY que rompe f (x) == f (y) => x == y

segunda excepción:!

NaN = NaN

Este es una advertencia especial de NotaNumber que permite averiguar si un número es un NaN en sistemas que no tienen una función de prueba disponible (sí, eso sucede).

Cuestiones relacionadas