Aquí es cómo iba a comprobar la igualdad, sin un "fudge factor":
if (
// Test 1: Very cheap, but can result in false negatives
a==b ||
// Test 2: More expensive, but comprehensive
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon())
std::cout << "The numbers are equal\n";
Explicación
La primera prueba es una simple comparación. Por supuesto, todos sabemos que comparar los valores de precisión doble puede hacer que se los considere desiguales, incluso cuando sean lógicamente equivalentes.
Un valor de punto flotante de doble precisión puede contener los quince dígitos más significativos de un número (en realidad ≈15.955 dígitos). Por lo tanto, queremos llamar dos valores iguales si (aproximadamente) coinciden sus primeros quince dígitos. Para decirlo de otra manera, queremos llamarlos iguales si están dentro de un épsilon escalado entre sí. Esto es exactamente lo que calcula la segunda prueba.
Puede elegir agregar más margen de acción que un épsilon de escala simple, debido a que los errores de coma flotante más importantes se arrastran como resultado del cálculo iterativo. Para ello, agregue un factor de error en el lado derecho de la comparación de la segunda prueba:
double error_factor=2.0;
if (a==b ||
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*
error_factor)
std::cout << "The numbers are equal\n";
no le puede dar un valor fijo para el error_factor
, ya que dependerá de la cantidad de error que se arrastra en su cómputos. Sin embargo, con algunas pruebas, debe poder encontrar un valor razonable que se adapte a su aplicación. Tenga en cuenta que agregar un factor de error (arbitrario) basado únicamente en la especulación lo pondrá de nuevo en el territorio del factor de dulce de azúcar.
Resumen
Usted puede envolver la siguiente prueba en un (n inline) Función:
inline bool logically_equal(double a, double b, double error_factor=1.0)
{
return a==b ||
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*
error_factor;
}
Huele la tarea, así que por favor agregue la etiqueta * tarea * si ese es el caso. –
Es curioso lo lejos que puede viajar ese olor ... –
@ user484955: ¿Realmente sabes qué significa 'while (a, b! = '|')'? –