Pourquoi% f imprime-t-il de grandes valeurs lorsque des constantes à virgule flottante sont passées au lieu de variables?

9

Dans le programme donné, pourquoi ai-je obtenu des résultats différents pour chacun des printfs?

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

Et il affiche la sortie suivante:

44000002048.000000
44000000000.000000
user10056563
la source
4
Jusqu'à présent, les réponses expliquent qu'il 4.4e10s'agit d'une doubleconstante qui est convertie en floatlors de l'initialisation de cmais conservée comme une doublefois passée à printf. Cependant, vous voudrez peut-être aussi savoir que l'ajout d'un fsuffixe en fait une floatconstante: l'impression 4.4e10faffichera la même valeur que celle résultant de l'initialisation cà 4.4e10f. Il peut être important de distinguer les floatconstantes des doubleconstantes pour effectuer un travail de qualité avec l'arithmétique à virgule flottante.
Eric Postpischil
Cette méthode de conversion porte-t-elle un nom? Je veux en savoir plus.
user10056563
Voulez-vous savoir quand la conversion de doubleà floatse produit en langage C? Ou voulez-vous savoir quelles valeurs résultent de la conversion, c'est-à-dire quels effets la conversion a? Ou autre chose?
Eric Postpischil
Je ne remets en question ni les réponses ici ni la norme mais, quand j'étais jeune et que j'apprenais, Cnous utilisions printf("%f",x)pour un floatet printf("%lf",x)pour un double. Quand les choses ont-elles changé? Et comment imprimer explicitement un (simple) float- printf("%hf",x)??
Adrian Mole
2
@Adrian %lfdans printf est la même chose que %f. Un floatdans un argument variable est converti en un doublepar le compilateur, tout comme un shortest converti en un int.
SS Anne

Réponses:

9

A floatest un type qui contient un nombre à virgule flottante 32 bits, tandis que la constante 4.4e10représente a double, qui contient un nombre à virgule flottante 64 bits (c'est-à-dire un nombre à virgule flottante à double précision)

Lorsque vous attribuez 4.4e10à c, la valeur 4.4e10ne peut pas être représentée avec précision (une erreur d'arrondi dans un paramètre appelé la mantisse) et la valeur la plus proche possible (44000002048) est stockée. Lorsqu'il est transmis à printf, il est promu à nouveau double, y compris l'erreur d'arrondi.

Dans le second cas, la valeur est a doubletout le temps, sans rétrécissement ni élargissement, et il se trouve que a doublepeut représenter exactement la valeur.

S'il s'agit d'un comportement indésirable, vous pouvez le déclarer ccomme un doublepour un peu plus de précision (mais attention, vous finirez toujours par atteindre des limites de précision).

nanofarad
la source
3

Vous imprimez en fait les valeurs de deux types différents ici.

Dans le premier cas, vous attribuez une valeur à une variable de type float. La précision de a floatest d'environ 6 ou 7 chiffres décimaux, donc à moins que la valeur ne puisse être représentée exactement, vous verrez la valeur la plus proche qui peut être représentée par ce type.

Dans le second cas, vous passez la constante de 4.4e10type double. Ce type a environ 16 chiffres décimaux de précision et la valeur se situe dans cette plage, la valeur exacte est donc imprimée.

dbush
la source
Pourquoi il imprime spécifiquement 2048 à la fin?
user10056563
@ user10056563 Parce que c'est le nombre le plus proche de 4.4e10 qui peut être stocké dans un flottant de 32 bits.
dbush