Comparación de punto flotante

int main() { float a = 0.7; float b = 0.5; if (a < 0.7) { if (b < 0.5) printf("2 are right"); else printf("1 is right"); } else printf("0 are right"); } 

Hubiera esperado que la salida de este código fuera 0 are right . Pero para mi consternación, la salida es 1 is right ¿por qué?

 int main() { float a = 0.7, b = 0.5; // These are FLOATS if(a < .7) // This is a DOUBLE { if(b < .5) // This is a DOUBLE printf("2 are right"); else printf("1 is right"); } else printf("0 are right"); } 

Los flotantes son promovidos a dobles durante la comparación, y como los flotadores son menos precisos que los dobles, 0.7 como flotante no es lo mismo que 0.7 como doble. En este caso, 0.7 como flotante se vuelve inferior a 0.7 como el doble cuando se promueve. Y como dijo Christian, 0.5 es una potencia de 2 siempre representada exactamente, por lo que la prueba funciona como se esperaba: 0.5 < 0.5 es falso.

Entonces o bien:

  • Cambie float a double , o:
  • Cambie .7 y .5 a .7f y .5f ,

y obtendrás el comportamiento esperado.

El problema es que las constantes con las que se compara no son float . Además, al cambiar sus constantes a algo que se puede representar fácilmente, como un factor de 5 , hará que diga que 0 is right . Por ejemplo,

 main() { float a=0.25,b=0.5; if(a<.25) { if(b<.5) printf("2 are right"); else printf("1 is right"); } else printf("0 are right"); } 

Salida:

0 are right

Esta pregunta SO en la forma más efectiva para flotación y comparación doble cubre este tema.

Además, este artículo en Cygnus sobre la comparación de números en coma flotante nos da algunos consejos:

Los formatos IEEE float y double se diseñaron para que los números estén "ordenados lexicográficamente", lo que - en palabras del arquitecto de IEEE William Kahan significa "si se ordenan dos números de punto flotante en el mismo formato (digamos x

Esto significa que si tomamos dos flotadores en la memoria, interpretamos su patrón de bits como enteros y los comparamos, podemos decir cuál es más grande, sin hacer una comparación en coma flotante. En el lenguaje C / C ++, esta comparación se ve así:

 if (*(int*)&f1 < *(int*)&f2) 

Esta encantadora syntax significa tomar la dirección de f1, tratarla como un puntero entero y desreferenciarla. Todas esas operaciones de puntero parecen costosas, pero básicamente todas se cancelan y solo significan 'tratar a f1 como un entero'. Como aplicamos la misma syntax a f2, toda la línea significa 'compare f1 y f2, utilizando sus representaciones en memoria interpretadas como enteros en lugar de flotantes'.

Se debe a problemas de redondeo al convertir de flotante a doble

En general, comparar la igualdad con las carrozas es un asunto peligroso (que es lo que estás haciendo cuando estás comparando directamente en el límite de>), recuerda que en decimales ciertas fracciones (como 1/3) no se pueden express exactamente, las mismas se puede decir de binario,

0.5= 0.1 , será lo mismo en flotante o doble.

0.7=0.10110011001100 etc. para siempre, 0.7 no se puede representar exactamente en binario, se obtienen errores de redondeo y pueden ser (muy ligeramente) diferentes entre float y double

Tenga en cuenta que al ir entre flotantes y dobles se corta un número diferente de decimales, de ahí sus resultados inconsistentes.

Además, por cierto, tienes un error en tu lógica de 0 que es correcto. Usted no marca b cuando su salida 0 es correcta. Pero todo es un poco misterioso en lo que realmente estás tratando de lograr. Las comparaciones de puntos flotantes entre flotantes y dobles tendrán variaciones, minutos, por lo que debe comparar con una variación delta ‘aceptable’ para su situación. Siempre he hecho esto a través de funciones en línea que solo realizan el trabajo (lo hice una vez con una macro, pero eso es demasiado desordenado). De todos modos, yah, abundan los problemas de redondeo con este tipo de ejemplo. Lee el punto flotante y sabe que .7 es diferente de .7f y al asignar .7 a un flotante se convertirá un doble en un flotante, cambiando así la naturaleza exacta del valor. Pero, la suposición de progtwigción sobre b está mal desde que me revisaste y me di cuenta de eso 🙂