2009-10-01 6 views
1
int main(void){ 
    float x =1; 
    float y =2; 
    while (x<y){ 
     x = x +1 ; 
     y = y +1; 
} 
    printf("x is %d\n", x); 
    printf("y is %d\n", y); 
} 

Je me attends à x et y augmenter au point que nous manquons de bits, mais il semble que x et y est alway 0 dans ce cas ...Pourquoi x et y sont-ils toujours à 0 avec un flottant?

+3

Essayez printf ("x is% f \ n", x); –

+0

Cette erreur est facile à faire, mais difficile à faire par la personne qui l'a fait. Demandez-le à quelqu'un d'autre et vous obtiendrez la réponse dans une minute :) – Ashwin

+0

En fait, il n'y a pas de spécificateur de conversion printf pour les flottants. Le spécificateur de conversion '% f' attend un double argument: heureusement, les arguments float sont convertis en double lorsque printf() est appelé. Ma suggestion: n'utilisez jamais de flotteurs; toujours utiliser des doubles. – pmg

Répondre

16

Comme d'autres l'ont dit, vous devez utiliser le format %f pour imprimer des flotteurs, non %d, qui est pour les entiers. Il y a aussi %e, qui imprime le flottant en notation scientifique au lieu de la notation fixe, et il y a aussi %g, qui l'imprime en scientifique ou fixe, selon la plus courte des deux. La raison pour laquelle il imprime 0 est que les arguments flottants sont automatiquement convertis en doubles lorsqu'ils sont passés en arguments à des fonctions variées (c'est-à-dire des fonctions qui prennent un nombre d'arguments non spécifié) comme printf(). Les représentations des nombres 2 et 3 (les valeurs de x et y) en tant que doubles sont respectivement 0x4000000000000000 et 0x4008000000000000, tel que calculé par le IEEE-754 Floating-Point Conversion calculator.

Sur les machines little-endian (par exemple basées sur x86), le modificateur %d récupère les 4 octets suivants de la pile et les interprète comme un nombre entier. Donc, quand vous passez le float 2, il est converti en un double comme 0x4000000000000000, ce qui est 00 00 00 00 00 00 00 40 dans little-endian. Les quatre premiers octets font l'entier 0, c'est ce qui est imprimé.

Notez que si vous avez imprimé les deux chiffres dans une déclaration au lieu de deux, vous obtiendrez un résultat plus surprenant:

printf("x=%d y=%d\n", x, y); 
// Output: x=0 y=1073741824 

La plupart des compilateurs peuvent vous mettre en garde contre ces types d'erreurs si vous définissez le niveau d'alerte élevé assez. Avec GCC, vous devriez compiler avec l'option -Wformat (ou -Wall, qui inclut -Wformat), et il vous avertira lorsque vous essaierez d'imprimer un flotteur avec %d par accident.

+2

Exactement à droite, sauf que x et y doivent tous les deux être 2^24 lorsque les instructions printf sont atteintes (2^24 + 1 tours à 2^24 en simple précision). Comme un double, 2^24 est 0x4170000000000000, donc le reste de votre analyse se passe très bien. –

+0

(Et, comme toujours, tous les paris sont désactivés si vous utilisez un compilateur qui choisit de faire tout ou partie de l'évaluation flottante en extension 80-bit.) –

+0

Ceci est une bonne réponse !. – slashmais

3

Une chose: Vous ne devriez pas utiliser% d dans printf pour les flottants, utilisez% f,% e ou% g à la place

1

Je me attends à x et y pour augmenter au point que nous manquons de bits

Non, plutôt la boucle s'arrête lorsque vous manquez de précision. Je crois qu'à un certain point le nombre sera assez grand pour qu'un incrément de 1.0f soit trop petit pour être représenté, et x deviendra égal à y.

Lorsque vous corrigez votre formatage de sortie, je suppose que vous verrez que c'est le cas.

+0

Spécifiquement: 2^24, si votre compilateur fait réellement toute l'évaluation flottante en simple précision. –

0

% d est un nombre entier, utilisez% f.

Vous manquerez de bits mais pas exactement comme un nombre entier, vous déborderez éventuellement l'exposant et cela devrait provoquer une exception, bien que vous ne le sachiez probablement pas. J'oublie si cela conduit à un nan ou une infinité. Ce qui fait le moins que d'avoir envie de jouer. Je me demande pourquoi la boucle while ne fonctionne pas pour toujours.

Questions connexes