¿Cómo se compara la flotación y el doble teniendo en cuenta la pérdida de precisión?
¿ Cuál sería la forma más eficiente de comparar dos double
o dos float
valores?
Simplemente hacer esto no es correcto:
bool CompareDoubles1 (double A, double B)
{
return A == B;
}
Pero algo como:
bool CompareDoubles2 (double A, double B)
{
diff = A - B;
return (diff < EPSILON) && (-diff < EPSILON);
}
Parece desperdiciar el procesamiento.
¿Alguien conoce un comparador de flotadores más inteligente?
Tenga mucho cuidado al utilizar cualquiera de las otras sugerencias. Todo depende del contexto.
He pasado mucho tiempo rastreando errores en un sistema que suponía a==b
que si |a-b|<epsilon
. Los problemas subyacentes fueron:
La presunción implícita en un algoritmo de que si
a==b
yb==c
entoncesa==c
.Usando el mismo épsilon para líneas medidas en pulgadas y líneas medidas en mils (0,001 pulgadas). Eso es
a==b
pero1000a!=1000b
. (Por esoAlmostEqual2sComplement
pide el épsilon o max ULPS).¡El uso del mismo épsilon tanto para el coseno de ángulos como para la longitud de líneas!
Usar una función de comparación de este tipo para ordenar elementos en una colección. (En este caso, el uso del operador integrado de C++
==
para dobles produjo resultados correctos).
Como dije: todo depende del contexto y del tamaño esperado de a
y b
.
Por cierto, std::numeric_limits<double>::epsilon()
es una "máquina épsilon". Es la diferencia entre 1.0
y el siguiente valor representable por un doble. Supongo que podría usarse en la función de comparación, pero solo si los valores esperados son menores que 1. (Esto es en respuesta a la respuesta de @cdv...)
Además, si básicamente tiene int
aritmética doubles
(aquí usamos dobles para mantener valores int en ciertos casos), su aritmética será correcta. Por ejemplo 4.0/2.0
será lo mismo que 1.0+1.0
. Esto es siempre y cuando no hagas cosas que resulten en fracciones ( 4.0/3.0
) o no salgan del tamaño de un int.
La comparación con un valor épsilon es lo que hace la mayoría de la gente (incluso en la programación de juegos).
Sin embargo, deberías cambiar un poco tu implementación:
bool AreSame(double a, double b)
{
return fabs(a - b) < EPSILON;
}
Editar: Christer ha agregado una gran cantidad de información excelente sobre este tema en una publicación de blog reciente . Disfrutar.