2010-11-29 8 views
5
void main() 
{ 
    float a = 0.7; 

    if (a < 0.7) 
     printf("c"); 
    else 
     printf("c++"); 
} 

En la pregunta anterior para 0.7, se imprimirá "c", pero para 0.8, se imprimirá "C++". ¿Por qué?representación exacta de los puntos flotantes en c

¿Y cómo se representa una flotación en forma binaria?

En algunos lugares, se menciona que internamente 0.7 se almacenará como 0.699997, pero 0.8 como 0.8000011. ¿Porque?

+0

Tenga en cuenta que 'a <0.7' primero convierte la versión de 32 bits de' a' a double (lo que da como resultado una representación imprecisa de 64 bits) y la compara con la versión de 0.7 bits menos precisa de 0.7. – Kos

Respuesta

12

básicamente con el flotador que presentamos lo mejor de 32 bits que codifican

VALUE = SIGN * MANTISSA * 2^(128 - EXPONENT) 
32-bits = 1-bit 23-bits    8-bits 

y que se almacena como

MSB     LSB 
[SIGN][EXPONENT][MANTISSA] 

ya que sólo recibe 23 bits, que es la cantidad de "precisión" se puede almacenar. Si está tratando de representar una fracción que es irracional (o repetitiva) en la base 2, la secuencia de bits se "redondeará" en el bit 23 °.

0.7 de base 10 es de 7/10, que en binario es 0b111/0b1010 que se obtiene:

0.1011001100110011001100110011001100110011001100110011... etc 

Dado que este se repite, en precisión fija no hay manera de representar exactamente la misma. Lo mismo ocurre con 0.8, que en binario es:

0.1100110011001100110011001100110011001100110011001101... etc 

para ver lo que el valor de precisión fija de estos números es que hay que "cortarles el paso" en el número de bits de usted y hace la matemáticas. El único truco es que el 1 principal está implícito y no almacenado, por lo que técnicamente obtienes un poco más de precisión. Debido al redondeo, el último bit será un 1 o un 0 dependiendo del valor del bit truncado.

Entonces el valor de 0.7 es efectivamente 11,744,051/2^24 (sin efecto de redondeo) = 0,699999988 y el valor de 0,8 es efectivamente 13,421,773/2^24 (redondeado hacia arriba) = 0,800000012.

Eso es todo lo que hay que hacer :)

-2

Las comparaciones de puntos flotantes son no confiables, haga lo que haga. Debe usar una comparación tolerante de umbral/épsilon de puntos flotantes.

Prueba IEEE-754 Floating-Point Conversion y mira lo que obtienes. :)

4

La representación interna es IEE754.

También puede usar this calculator para convertir decimal a flotante, espero que esto ayude a entender el formato.

+0

Tenga en cuenta que el estándar de lenguaje C no exige el uso de IEEE754 (al menos no a partir de n1256); eso depende de la plataforma. Habiendo dicho eso, no puedo pensar en una plataforma de escritorio actual que no la use. –

+0

El enlace 'this calculator' ya no funciona. – Gabe

+0

He arreglado el enlace. La calculadora se actualizó a una nueva versión. La [versión original] (http://babbage.cs.qc.edu/IEEE-754.old/Decimal.html) aún está disponible, pero la nueva versión parece ser mejor. –

0

float s se almacenarán como se describe en IEEE 754: 1 bit para el signo, 8 para un exponente sesgado, y el resto que almacena la parte fraccionaria.

Piense en los números representables como flotantes como puntos en la recta numérica, a cierta distancia; frecuentemente, las fracciones decimales caerán entre estos puntos, y se usará la representación más cercana; esto lleva a los resultados contraintuitivos que describes.

"What every computer scientist should know about floating point arithmetic" debe responder a todas sus preguntas en detalle.

0

Si usted quiere saber cómo float/double se presenta en C (y casi todos los idiomas), por favor refert al estándar de aritmética de punto flotante (IEEE 754) http://en.wikipedia.org/wiki/IEEE_754-2008

Using single-precision floats as an example, here is the bit layout: 
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm meaning 
31        0 bit # 
s = sign bit, e = exponent, m = mantissa 
0

Otro buen recurso para ver cómo los números de punto flotante se almacenan como binarios en las computadoras es la página de Wikipedia en IEEE-754.

+0

Vaya, el apilador me ganó. – pr1268

0

Los números de coma flotante en C/C++ están representados en formato estándar IEEE-754. Hay muchos artículos en internet que describen con mucho más detalle que aquí, cómo se representa exactamente un punto flotante en binario. Una simple búsqueda de IEEE-754 debería iluminar el misterio.

0

0.7 es un literal numérico; su valor es el número real matemático 0.7, redondeado al valor doble más cercano.

Después de inicializar float a = 0.7, el valor de a es 0.7 redondeado a flotar, es decir el número real 0.7, redondeado al valor doble más cercano, redondeado al valor flotante más cercano. Excepto por una gran coincidencia, no esperarías que a sea igual a 0.7.

"if (a < 0.7)" compara 0,7 redondeado al doble y luego a flotar con el número 0,7 redondeado al doble. Parece que en el caso de 0.7, el redondeo produjo un número menor. Y en el mismo experimento con 0.8, redondeando 0.8 a flotar producirá un número mayor que 0.8.

Cuestiones relacionadas