11
votes

Double équivaut à 0 problème en c

Je mettais en place un algorithme pour calculer des grumes naturelles dans C. xxx pré>

comme indiqué par la déclaration d'impression, TMP est égal à 0,0, cependant, cependant, la boucle continue. Ce qui pourrait causer cela? P>

Je suis sur Fedora 14 amd64 et compilair avec: p> xxx pré>


Exemple: P>

$ ./taylor_ln 2
(1.0 / 1) * (pow(((2 - 1.0) / (2 + 1.0)), 1)) = 0.333333
(1.0 / 3) * (pow(((2 - 1.0) / (2 + 1.0)), 3)) = 0.012346
(1.0 / 5) * (pow(((2 - 1.0) / (2 + 1.0)), 5)) = 0.000823
(1.0 / 7) * (pow(((2 - 1.0) / (2 + 1.0)), 7)) = 0.000065
(1.0 / 9) * (pow(((2 - 1.0) / (2 + 1.0)), 9)) = 0.000006
(1.0 / 11) * (pow(((2 - 1.0) / (2 + 1.0)), 11)) = 0.000001
(1.0 / 13) * (pow(((2 - 1.0) / (2 + 1.0)), 13)) = 0.000000
(1.0 / 15) * (pow(((2 - 1.0) / (2 + 1.0)), 15)) = 0.000000
(1.0 / 17) * (pow(((2 - 1.0) / (2 + 1.0)), 17)) = 0.000000
(1.0 / 19) * (pow(((2 - 1.0) / (2 + 1.0)), 19)) = 0.000000
(1.0 / 21) * (pow(((2 - 1.0) / (2 + 1.0)), 21)) = 0.000000
and so on...


5 commentaires

Wow, quatre personnes ayant la même réponse en même temps.


Jetez un coup d'œil à: Stackoverflow.com/Questtions/4664662/... . Les nombres de points flottants peuvent être très difficiles si vous ne les connaissez pas bien.


@mgiuca: alors il doit avoir raison :-)


Si vous utilisez % g pour imprimer le numéro de point flottant au lieu de % f , vous verrez que ce n'est pas réellement zéro.


Dupliqué possible de lorsque vous comparez pour l'égalité, est-il correct d'utiliser == ?


5 Réponses :


2
votes

N'utilisez pas d'opérations d'égalité exactes lors de la gestion des numéros de points flottants. Bien que votre numéro puisse look em> comme 0 code>, il est susceptible d'être quelque chose comme 0.00000000000000000000001 code>.

Vous verrez ceci si vous utilisez %. 50f code> au lieu de % f code> dans vos chaînes de format. Ce dernier utilise une valeur raisonnable pour les décimales (6 dans votre cas), mais l'ancien indique explicitement que vous voulez beaucoup. P>

Pour la sécurité, utilisez un delta pour vérifier s'il est assez proche, tel que: P>

if (fabs (val) < 0.0001) {
    // close enough.
}


0 commentaires

12
votes

La comparaison de points flottants est exacte, donc 10 ^ -10 code> n'est pas le même que 0,0 code>.

Fondamentalement, vous devriez comparer à une différence tolérable, Dites 10 ^ -7 code> en fonction du nombre de décimales que vous écrivez, cela peut être accompli comme suit: P>

while(fabs(tmp) > 10e-7)


5 commentaires

Et voici le lien obligatoire: Ce que chaque informatique devrait savoir sur l'arithmétique de points flottants


Deux choses: ABS est une opération entière; Utilisez fabs . Et vous voulez alors que plus grand que certains seuils, pas moins que.


@chrisaycock: Vous auriez dû faire une réponse ... c'est (ou la version simplifiée) est la bonne réponse à la plupart des questions relatives au point flottant.


Les questions @Ben de cette variété sont posées sur si tous les jours. Je pense que quiconque au-dessus d'un certain niveau de réputation a posté ce lien au moins une fois dans sa carrière.


@chrisaycock: J'ai certainement. Vraiment la seule chose qui me surprend de cette question est qu'elle n'a pas encore été fermée comme une duplicata, avec cinq questions différentes proposées comme "originale".



0
votes

juste parce qu'un numéro s'affiche comme "0.000000" ne signifie pas qu'il est égal à 0,0. L'affichage décimal des nombres a moins de précision qu'un double stockage peut être double.

Il est possible que votre algorithme passe à un point où il est très proche de 0, mais la prochaine étape se déplace si peu qu'elle tourne à la même chose était auparavant, et il ne devient donc jamais plus près de 0 (passe simplement dans une boucle infinie).

En général, vous ne devez pas comparer les numéros de point flottant avec == et ! = . Vous devez toujours vérifier s'ils se trouvent dans une certaine petite gamme (généralement appelée Epsilon). Par exemple: xxx

alors il s'arrête quand il est raisonnablement proche de 0.


0 commentaires

0
votes

L'instruction d'impression affiche une valeur arrondie, elle n'imprime pas la précision la plus élevée possible. Donc, votre boucle n'a pas encore atteint zéro.

(et, comme d'autres personnes ont mentionné, en raison de problèmes d'arrondi, il pourrait ne jamais y arriver. La comparaison de la valeur contre une petite limite est donc plus robuste que la comparaison de l'égalité avec 0,0.)


0 commentaires

0
votes

Beaucoup de discussions sur la cause, mais voici une solution alternative: xxx

Cette approche se concentre sur si chaque valeur décroissante du TMP fait une différence tangible en résumé. Il est plus facile que de travailler certains seuils de 0 à quel TMP devient insignifiant et se termine probablement plus tôt sans changer le résultat.

Notez que lorsque vous résumez un nombre relativement gros, les chiffres significatifs de le résultat limite la précision. À titre de contraste, si vous sumez plusieurs petits, ajoutez-le à celui-ci au grand, vous pourriez alors en avoir assez pour baisser le grand un peu. Dans votre algorithme, de petites valeurs TMP n'étaient pas résumées de toute façon, il n'y a donc pas d'accumulation sauf si chacun n'affecte pas réellement la somme - d'où l'approche ci-dessus fonctionne sans plus de compromettre la précision.


0 commentaires