Question

J'ai donc une fonction qui ressemble à ceci :

float function(){
    float x = SomeValue;
    return x / SomeOtherValue;
}

À un moment donné, cette fonction déborde et renvoie une valeur négative très importante.Pour essayer de localiser exactement où cela se produisait, j'ai ajouté une instruction cout pour que la fonction ressemble à ceci :

float function(){
    float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

et ça a marché !Bien sûr, j'ai complètement résolu le problème en utilisant un double.Mais je suis curieux de savoir pourquoi la fonction a fonctionné correctement lorsque je l'ai calculée.Est-ce typique, ou pourrait-il y avoir un bug ailleurs qui me manque ?

(Si cela peut vous aider, la valeur stockée dans le float n'est qu'une valeur entière, et pas particulièrement grande.Je l'ai juste mis dans un flotteur pour éviter de lancer.)

Était-ce utile?

La solution

Bienvenue dans le monde merveilleux de la virgule flottante.La réponse que vous obtiendrez dépendra probablement du modèle à virgule flottante avec lequel vous avez compilé le code.

Cela se produit en raison de la différence entre la spécification IEEE et le matériel sur lequel le code est exécuté.Votre processeur dispose probablement de registres à virgule flottante de 80 bits qui sont utilisés pour contenir la valeur flottante de 32 bits.Cela signifie qu'il y a beaucoup plus de précision lorsque la valeur reste dans un registre que lorsqu'elle est forcée à une adresse mémoire (également appelée « homing » du registre).

Lorsque vous passiez la valeur à cout, le compilateur devait écrire la virgule flottante en mémoire, ce qui entraînait une perte de précision et un comportement intéressant dans les cas de débordement WRT.

Voir la documentation MSDN sur VC++ commutateurs à virgule flottante.Vous pouvez essayer de compiler avec /fp:strict et voir ce qui se passe.

Autres conseils

L'impression d'une valeur sur cout ne devrait en aucun cas modifier la valeur du paramètre.

Cependant, j'ai constaté un comportement similaire, l'ajout d'instructions de débogage entraîne une modification de la valeur.Dans ces cas, et probablement celui-ci aussi, je suppose que les instructions supplémentaires entraînaient un comportement différent de l'optimiseur du compilateur, donc générez un code différent pour votre fonction.

L'ajout de l'instruction cout signifie que la valeur de x est utilisée directement.Sans cela, l'optimiseur pourrait supprimer la variable, modifiant ainsi l'ordre du calcul et donc la réponse.

En passant, c'est toujours une bonne idée de déclarer des variables immuables en utilisant const:

float function(){
    const float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

Cela vous évitera entre autres de transmettre involontairement vos variables à des fonctions susceptibles de les modifier via desconst les références.

cout provoque une référence à la variable, ce qui amènera souvent le compilateur à la forcer à la diffuser dans la pile.

Puisqu'il s'agit d'un flottant, sa valeur sera probablement tronquée par rapport à la représentation double ou longue double qu'elle aurait normalement.

L'appel de n'importe quelle fonction (non-inline) qui prend un pointeur ou une référence à x devrait finir par provoquer le même comportement, mais si le compilateur devient plus intelligent plus tard et apprend à l'inline, vous serez également foutu :)

Je ne pense pas que le cout ait un effet sur la variable, le problème devrait être ailleurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top