¿Por qué% f imprime valores grandes cuando se pasan constantes de coma flotante en lugar de variables?

9

En el programa dado, ¿por qué obtuve resultados diferentes para cada uno de los printfs?

#include <stdio.h>
int main()
{
    float c = 4.4e10;
    printf("%f\n", c);
    printf("%f\n", 4.4e10);
    return 0;
}

Y muestra el siguiente resultado:

44000002048.000000
44000000000.000000
usuario10056563
fuente
44
Las respuestas hasta ahora explican que 4.4e10es una doubleconstante a la que se convierte floaten la inicialización cpero que se mantiene como una doublecuando se pasa a printf. Sin embargo, es posible que también le interese saber que la adición de un fsufijo hace que sea una floatconstante: La impresión 4.4e10fmostrará el mismo valor que resulta de inicialización ca 4.4e10f. Distinguir floatconstantes de doubleconstantes puede ser importante para hacer un trabajo de calidad con aritmética de punto flotante.
Eric Postpischil
¿Este método de conversión tiene algún nombre? Quiero leer sobre eso.
user10056563
¿Desea saber cuándo se produce la conversión de doublea floaten el lenguaje C? ¿O desea saber qué valores resultan de la conversión, es decir, qué efectos tiene la conversión? ¿O algo mas?
Eric Postpischil
No estoy cuestionando ni las respuestas aquí ni el estándar, pero cuando era joven y aprendía Csolíamos usar printf("%f",x)un floaty printf("%lf",x)para un double. ¿Cuándo cambiaron las cosas? ¿Y cómo se imprime explícitamente un (único) float- printf("%hf",x)??
Adrian Mole
2
@Adrian %lfen printf es lo mismo que %f. A floaten un argumento variable es convertido en a doublepor el compilador, al igual que a shortse convierte en an int.
SS Anne

Respuestas:

9

A floates un tipo que contiene un número de coma flotante de 32 bits, mientras que la constante 4.4e10representa a double, que contiene un número de coma flotante de 64 bits (es decir, un número de coma flotante de doble precisión)

Cuando se asigna 4.4e10a c, el valor 4.4e10no puede representarse con precisión (un error de redondeo en un parámetro llamado mantisa), y se almacena el valor más cercano posible (44000002048). Cuando se pasa a printf, se vuelve a promoverdouble , incluido el error de redondeo.

En el segundo caso, el valor es a doubletodo el tiempo, sin estrecharse ni ensancharse, y resulta que a doublepuede representar el valor exactamente.

Si este es un comportamiento indeseable, puede declarar ccomo un doublepoco más de precisión (pero tenga en cuenta que eventualmente alcanzará los límites de precisión).

nanofaradio
fuente
3

En realidad, está imprimiendo los valores de dos tipos diferentes aquí.

En el primer caso, está asignando un valor a una variable de tipo float. La precisión de a floates de aproximadamente 6 o 7 dígitos decimales, por lo que, a menos que el valor pueda representarse exactamente, verá el valor más cercano que ese tipo puede representar.

En el segundo caso, está pasando la constante 4.4e10que tiene tipo double. Este tipo tiene alrededor de 16 dígitos decimales de precisión, y el valor está dentro de ese rango, por lo que se imprime el valor exacto.

dbush
fuente
¿Por qué imprime específicamente 2048 al final?
user10056563
@ user10056563 Porque ese es el número más cercano a 4.4e10 que puede almacenarse en un flotante de 32 bits.
dbush