problemas en la comparación de puntos flotantes

void main() { float f = 0.98; if(f <= 0.98) printf("hi"); else printf("hello"); getch(); } 

Estoy obteniendo este problema aquí. Al usar diferentes valores de coma flotante, recibo resultados diferentes. ¿Por qué está pasando esto?

f usa precisión float , pero 0.98 tiene double precisión double por defecto, por lo que la afirmación f <= 0.98 se compara con double precisión.

Por lo tanto, f se convierte en un double en la comparación, pero puede hacer que el resultado sea ligeramente mayor que 0,98.

Utilizar

 if(f <= 0.98f) 

o usa un double para f lugar.


En detalle ... suponiendo que el float es de precisión simple IEEE y el double es de doble precisión IEEE .

Este tipo de números de punto flotante se almacenan con una representación de base 2. En base-2 este número necesita una precisión infinita para representarlo ya que es un decimal repetido:

 0.98 = 0.1111101011100001010001111010111000010100011110101110000101000... 

Un float solo puede almacenar 24 bits de cifras significativas, es decir,

  0.111110101110000101000111_101... ^ round off here = 0.111110101110000101001000 = 16441672 / 2^24 = 0.98000001907... 

Un double puede almacenar 53 bits de figuras significativas, por lo que

  0.11111010111000010100011110101110000101000111101011100_00101000... ^ round off here = 0.11111010111000010100011110101110000101000111101011100 = 8827055269646172 / 2^53 = 0.97999999999999998224... 

Entonces el 0.98 se volverá un poco más grande en el float y más pequeño en el double .

Es porque los valores de coma flotante no son representaciones exactas del número. Todos los números base diez deben estar representados en la computadora como números base 2. Es en esta conversión que se pierde la precisión.

Lea más sobre esto en http://en.wikipedia.org/wiki/Floating_point


Un ejemplo (de encontrar este problema en mis días de VB6)

Para convertir el número 1.1 a un número de coma flotante de precisión simple, necesitamos convertirlo a binario. Hay 32 bits que deben crearse.

El bit 1 es el bit de signo (es negativo [1] o posición [0]) Los bits 2-9 son para el valor exponencial Los bits 10-32 son para la mantisa (también conocido como, básicamente, el coeficiente de notación científica)

Así que para 1.1 el valor de punto flotante único se almacena de la siguiente manera (este es el valor truncado, el comstackdor puede redondear el bit menos significativo detrás de las escenas, pero todo lo que hago es truncarlo, lo cual es ligeramente menos preciso pero no cambia los resultados de este ejemplo):

 s --exp--- -------mantissa-------- 0 01111111 00011001100110011001100 

Si notas en la mantisa, está el patrón de repetición 0011. 1/10 en binario es como 1/3 en decimal. Continúa para siempre Entonces, para recuperar los valores del valor de coma flotante de precisión simple de 32 bits, primero debemos convertir el exponente y la mantisa en números decimales para poder usarlos.

signo = 0 = un número positivo

exponente: 01111111 = 127

mantisa: 00011001100110011001100 = 838860

Con la mantisa necesitamos convertirlo a un valor decimal. La razón es que hay un entero implícito por delante del número binario (es decir, 1.00011001100110011001100). El número implícito se debe a que la mantisa representa un valor normalizado que se utilizará en la notación científica: 1.0001100110011 …. * 2 ^ (x-127).

Para obtener el valor decimal de 838860 simplemente dividimos por 2 ^ -23 ya que hay 23 bits en la mantisa. Esto nos da 0.099999904632568359375. Agregue el implícito 1 a la mantisa nos da 1.099999904632568359375. El exponente es 127 pero la fórmula requiere 2 ^ (x-127).

Así que aquí está la matemática:

(1 + 099999904632568359375) * 2 ^ (127-127)

1.099999904632568359375 * 1 = 1.099999904632568359375

Como puede ver, 1.1 no está realmente almacenado en el valor de punto flotante único como 1.1.