Pregunta

Tengo esta línea de código simple:

float val = 123456.123456;

Cuando imprimo este val o miro en alcance, almacena el valor 123456.13

Ok, está bien, no puede almacenar todos esos dígitos tras punto solo en 4 bytes, pero ¿por qué hace 13 después del punto? ¿No debería ser 12?

(Usando VC ++ 2010 Express en Win32)

¿Fue útil?

Solución

Cuando se representa como un flotador, su número tiene un exponente de 16 (es decir, el valor es su Mantisse Times 2^16, o 65536). La mantis se convierte en

123456.123456 / 65536 = 1.8837909462890625

Para encajar en un flotador de 32 bits, la mantis se trunca a 23 bits, por lo que ahora se convierte en 1.883791. Cuando se multiplica de nuevo por 65536, se vuelve 123456.125.

Nota la 5 En la tercera posición después del punto decimal: la rutina de salida de C ++ que usó la redondea, haciendo que su número final se vea como 123456.13.

EDITAR Explicación del redondeo: (comentario de Rick Regan)

El redondeo ocurre primero en binario (a 24 bits), en la conversión decimal a binaria, y luego a decimal, en printf. El valor almacenado es 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125. Imprime como 123456.13, pero solo porque Visual C ++ usa el redondeo "redondo de cero".

Rick tiene un Artículo sobresaliente sobre el tema, también.

Si desea jugar con otros números y sus representaciones flotantes, aquí hay un Calculadora IEEE-754 muy útil.

Otros consejos

En binario, 123456.123456 es 11110001001000000.000111111001 ... (Infinito). Se redondea a 11110001001000000.001, o 123456.125. Que Rondas a 123456.13 cuando se imprime.

El valor almacenado en val es igual a 123456.125. Te estás poniendo .13 Porque lo estás redondeando:

float val = 123456.123456;
printf("%.4f %.2f\n", val, val);

producción: 123456.1250 123456.13

Debe usar el doble en este caso para evitar el truncamiento. El compilador también debe advertirte: "Advertencia C4305: 'Inicialización': Truncamiento de 'Double' a 'Flotar'".

Intente imprimir el valor de std::numeric_limits<float>::digits10. Esto es más o menos en hablar cuánta precisión en la base 10 tiene un flotador. Estás tratando de superarlo, por lo que está experimentando una pérdida de precisión (lo que significa que los dígitos más allá de los importantes no son realmente significativos).

Ver EG ¿Cuál es el significado de numeric_limits?u003Cdouble> :: dígitos10

Es totalmente dependiente del compilador. Compruébalo en GCC. Debería ser xxx.12

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top