El flotador de precisión Problema
Usted tiene dos problemas aquí, pero ambos vienen de la misma raíz
No se puede comparar con precisión los flotadores. No puedes restarlos o dividirlos con precisión. No puede contar nada precisamente para ellos. Cualquier operación con ellos podría (y casi siempre) traer algún error en el resultado. Incluso a=0.2f
no es una operación precisa. Las razones más profundas de eso están muy bien explicadas por los autores de las otras respuestas aquí. (Mi agradecimiento y votos para ellos por eso.)
Aquí viene su primer y más simple error. Nunca se debe, nunca se , Nunca, Nunca, NUNCA uso en ellos == o su equivalente en cualquier idioma. En lugar de a==b
, use Abs(a-b)<HighestPossibleError
en su lugar.
Pero este no es el único problema en su tarea.
Abs(1/y-x)<HighestPossibleError
tampoco funcionará. Al menos, no funcionará con la suficiente frecuencia. ¿Por qué?
Tomemos el par x = 1000 e y = 0.001. Tomemos el error relativo "inicial" de y para 10 -6.
(Error relativo = error/valor).
Los errores relativos de los valores se suman a la multiplicación y división.
1/y es aproximadamente 1000. Su error relativo es el mismo 10 -6. ("1" no tiene errores)
Eso hace un error absoluto = 1000 * 10 -6 = 0.001. Cuando resta x más tarde, ese error será todo lo que quede. (Se suman los errores absolutos al sumar y restar, y el error de x es insignificante.) Seguramente, no cuenta con errores tan grandes, seguramente HighestPossibleError se establecerá más bajo y su programa arrojaría un buen par de x, y
Entonces, las siguientes dos reglas para operaciones de flotante: trate de no dividir mayores valorador por uno menor y Dios lo salve de restar los valores cercanos después de eso.
Existen dos formas sencillas de solucionar este problema.
Por fundador lo de x, y tiene el mayor valor abs y dividir 1 por la mayor uno y sólo más tarde para restar el menor uno.
Si desea comparar 1/y against x
, mientras se está trabajando todavía con letras, no los valores, y sus operaciones que no hay errores, se multiplican ambos lados de la comparación por y y tiene 1 against x*y
. (Por lo general, debe verificar los signos en esa operación, pero aquí utilizamos valores abs, por lo tanto, está limpio.) La comparación de resultados no tiene división en absoluto.
En un camino más corto:
1/y V x <=> y*(1/y) V x*y <=> 1 V x*y
ya sabemos que la comparación como 1 against x*y
debe hacerse de modo:
const float HighestPossibleError=1e-10;
if(Abs(x*y-1.0)<HighestPossibleError){...
Eso es todo.
P.S. Si realmente lo necesita todo en una sola línea, utilice:
if(Abs(x*y-1.0)<1e-10){...
Pero es mal estilo. Yo no lo aconsejaría.
P.P.S. En su segundo ejemplo, el compilador optimiza el código para que configure z a 5 antes de ejecutar cualquier código. Entonces, verificar 5 contra 5 funciona incluso para carrozas.
http://docs.oracle.com/ cd/E19957-01/806-3568/ncg_goldberg.html – Mysticial
'((x * y) == 1)' tampoco? – Vyktor
He agregado algo de información en mi respuesta. Y +1 para una pregunta fructífera. – Gangnus