Pour la boucle en C++ à l'aide de double de casser une étape précoce, valeur limite pas atteint
J'ai un simple programme en C++ compilé avec gcc 4.2.4 sur 32 bits Ubuntu 8.04. Il a un for
-la boucle dans laquelle un double
variable est incrémentée à partir de zéro à un, avec une certaine étape de la taille. Lorsque la taille du pas est 0.1
, le comportement est ce que j'attendais. Mais quand la taille du pas est '0.05', la boucle s'arrête après 0.95
. Quelqu'un peut me dire pourquoi ce qui se passe? La sortie suit le code source ci-dessous.
#include <iostream>
using namespace std;
int main()
{
double rangeMin = 0.0;
double rangeMax = 1.0;
double stepSize = 0.1;
for (double index = rangeMin; index <= rangeMax; index+= stepSize)
{
cout << index << endl;
}
cout << endl;
stepSize = 0.05;
for (double index = rangeMin; index <= rangeMax; index+= stepSize)
{
cout << index << endl;
}
return 0;
}
SORTIE
sarva@savija-dev:~/code/scratch$ ./a.out
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
0
0.05
0.1
0.15
0.2
0.25
0.3
0.35
0.4
0.45
0.5
0.55
0.6
0.65
0.7
0.75
0.8
0.85
0.9
0.95
sarva@savija-dev:~/code/scratch$
- peut-être à virgule flottante de problème, j'ai vérifier!!!
- Ne pas accepter des réponses tout de suite! Donner aux gens un certain temps pour obtenir à votre question et le type de réponse.
Vous devez vous connecter pour publier un commentaire.
Lors de l'utilisation de valeurs à virgule flottante pas tous exactement la valeur représentable,
0.95+0.05 > 1
parce que0.95
n'est pas exactement représentable par undouble
valeur.Voir ce que Wikipedia a à dire à propos de virgule flottante de précision.
Si vous regardez la À virgule flottante IEEE de convertisseur vous verrez que la valeur de
0.95
en 64 bits à virgule flottante (double
) est0-01111111110-1110011001100110011001100110011001100110011001100110
en s'inscrivant dans une virgule flottante calculatrice vous obtenez la valeur est0.95000016
et l'ajout de0.05
à qui vous emmène sur le1.0
marque.C'est pourquoi vous devriez ne jamais utiliser de floating points dans les boucles (ou plus généralement de comparer le résultat à virgule flottante calcul d'un exacte valeur).
index
comme un entier, et de les comparerindex * stepSize
.Généralement, lorsque vous comparez des doubles, une simple comparaison n'est pas assez bon, et vous devriez les comparer "jusqu'à un niveau de précision". c'est à dire :
Le problème se produit en raison de la représentation des variables doubles.
Comme mentionné par d'autres, c'est une question bien connue en raison de l'imprécision de la représentation de certains nombres décimaux dans la mémoire. Je recommande fortement la lecture de Ce Que Tout Informaticien Devez Savoir À Propos De L'Arithmétique À Virgule Flottante et À virgule flottante IEEE de représentations du réel
les numéros de.
Vous ne devez pas utiliser == ou <= pour les doubles en raison de sa représentation interne. Sur la dernière étape, vous aurez
0.95000000000000029
. Au lieu de cela, vous pouvez utiliser le code suivant:Pour plus de détails, lire Ce Que Tout Informaticien Devez Savoir À Propos De L'Arithmétique À Virgule Flottante.
Plus précisément les décimales ne sont pas exactement fini représentation en arithmétique à virgule flottante.
Vous avez besoin de lire Goldberg a Ce Que Tout Informaticien Devez Savoir À Propos De L'Arithmétique À Virgule Flottante.
Probablement la dernière
index
valeur serait comme1.00000001
.Comme d'autres l'ont dit, et pas à chaque nombre réel est exactement représentable comme une valeur à virgule flottante, de sorte que vous pouvez vous attendre à un petit, "aléatoire" erreur d'arrondi dans les calculs à virgule flottante. Il est similaire à ce qui se passe avec la normale de chiffres décimaux: 1/3 n'est pas exactement représentable à l'aide de trois chiffres après la virgule (0.33), donc (1/3)*3 deviendrait 0,99 et pas exactement 1.
Il est possible d'utiliser une sorte de "précision" dans vos comparaisons, mais je recommande d'éviter les nombres à virgule flottante pour les boucles, et au lieu d'utiliser des entiers.
Par exemple, votre boucle
pourrait être remplacé par quelque chose le long des lignes de
Cela est dû à l'imprécision de la représentation décimale des fractions en nombres à virgule flottante. Votre taille n'est pas réellement 0,1 ou 0,05, c'est une autre valeur qui est très étroite. La légère erreur s'accumule comme vous allez à travers la boucle.
Pour résoudre ce problème, vous devez éviter de comparer des nombres à virgule flottante pour l'égalité.
Voir cette sortie: (floating point accuarcy)
Comme les réponses précédentes , il n'est pas exact d'employer des nombres non entiers pour des boucles , Alors je vous suggère de faire comme l'exemple suivant si vous gardez l'exactitude des nombres entiers et vous pouvez obtenir le nombre de décimales que vous souhaitez: