floating point - maquina - ¿Realmente "epsilon" garantiza algo en los cálculos de coma flotante?
epsilon significado (2)
Epsilon se usa para determinar si dos números sujetos a error de redondeo son lo suficientemente cercanos para ser considerados "iguales". Tenga en cuenta que es mejor probar fabs(b/c - 1) < EPS
que fabs(bc) < EPS
, y aún mejor - gracias al diseño de flotantes IEEE - para probar abs(*(int*)&b - *(int*)&c) < EPSI
(donde EPSI es un pequeño entero).
Su problema es de naturaleza diferente, y probablemente justifique probar el resultado en lugar de las entradas.
Para hacer que el problema sea corto, digamos que quiero calcular la expresión a / (b - c)
en float
s.
Para asegurarme de que el resultado sea significativo, puedo verificar si b
y c
son iguales:
float EPS = std::numeric_limits<float>::epsilon();
if ((b - c) > EPS || (c - b) > EPS)
{
return a / (b - c);
}
pero mis pruebas demuestran que no es suficiente para garantizar resultados significativos ni tampoco proporcionar un resultado si es posible.
Caso 1:
a = 1.0f;
b = 0.00000003f;
c = 0.00000002f;
Resultado: la condición if NO se cumple, pero la expresión produciría un resultado correcto 100000008 (en cuanto a la precisión de los flotadores).
Caso 2
a = 1e33f;
b = 0.000003;
c = 0.000002;
Resultado: la condición if se cumple, pero la expresión no produce un resultado significativo +1.#INF00
.
Encontré mucho más confiable para verificar el resultado, no los argumentos:
const float INF = numeric_limits<float>::infinity();
float x = a / (b - c);
if (-INF < x && x < INF)
{
return x;
}
Pero ¿para qué sirve épsilon y por qué todos dicen que épsilon es bueno para usar?
"debe usar un epsilon cuando se trata de flotadores" es una reacción instintiva de los programadores con una comprensión superficial de los cálculos de coma flotante, para las comparaciones en general (no solo a cero).
Esto generalmente no es útil porque no le indica cómo minimizar la propagación de errores de redondeo, no le indica cómo evitar problemas de cancelación o absorción, e incluso cuando su problema está relacionado con la comparación de dos flotadores, no te dice qué valor de épsilon es el correcto para lo que estás haciendo .
Si no ha leído lo que todos los científicos deberían saber sobre la aritmética de punto flotante , es un buen punto de partida. Además de eso, si está interesado en la precisión del resultado de la división en su ejemplo, debe estimar qué tan impreciso bc
se hizo con errores de redondeo previos , porque de hecho si bc
es pequeño, un pequeño error absoluto corresponde a un gran error error absoluto en el resultado. Si su preocupación es solo que la división no debe desbordarse, entonces su prueba (en el resultado) es correcta. No hay ninguna razón para probar un divisor nulo con números de punto flotante, solo prueba el desbordamiento del resultado, que captura tanto los casos en que el divisor es nulo como el divisor es tan pequeño que el resultado no es representable con cualquier precisión
En cuanto a la propagación de errores de redondeo, existen analizadores especializados que pueden ayudarlo a estimarlo, porque es una tarea tediosa hacerlo a mano.