Pourquoi vois-je une variable double initialisée à une valeur telle que 21.4 sous la forme 21.399999618530273?

StackOverflow https://stackoverflow.com/questions/177506

  •  05-07-2019
  •  | 
  •  

Question

double r = 11.631;
double theta = 21.4;

Dans le débogueur, ils sont indiqués par 11.631000000000000 et 21.399999618530273 .

Comment puis-je éviter cela?

Était-ce utile?

La solution

Ces problèmes de précision sont dus au représentation interne de nombres à virgule flottante et vous ne pouvez rien faire pour l'éviter.

En passant, l’impression de ces valeurs au moment de l’exécution conduit souvent au résultat correct, du moins à l’aide de compilateurs C ++ modernes. Pour la plupart des opérations, ce n’est pas un problème.

Autres conseils

J'ai aimé les l'explication de Joel , qui traite d'un flottant binaire similaire. problème de précision de point dans Excel 2007:

  

Vous voyez combien il y a beaucoup de 0110 0110 0110 à la fin? En effet, 0.1 n'a pas de représentation exacte en binaire ... c'est un nombre binaire répété. C'est un peu comme si 1/3 n'avait pas de représentation décimale. 1/3 est 0.33333333 et vous devez continuer à écrire des 3 pour toujours. Si vous perdez patience, vous obtenez quelque chose d’inexact.

     

Vous pouvez donc imaginer comment, en décimal, si vous essayez de faire 3 * 1/3 et que vous n’avez pas le temps d’écrire des 3, le résultat que vous obtiendrez serait 0,99999999, pas 1, et se fâcher contre vous pour avoir tort.

Si vous avez une valeur telle que:

double theta = 21.4;

Et vous voulez faire:

if (theta == 21.4)
{
}

Vous devez être un peu intelligent, vous devrez vérifier si la valeur de thêta est vraiment proche de 21,4, mais pas nécessairement de cette valeur.

if (fabs(theta - 21.4) <= 1e-6)
{
}

Ceci est en partie spécifique à la plate-forme - et nous ne savons pas quelle plate-forme vous utilisez.

Il s’agit également en partie de savoir ce que vous voulez réellement voir. Le débogueur vous montre - dans une certaine mesure, de toute façon - la valeur précise stockée dans votre variable. Dans mon article sur les nombres à virgule flottante dans .NET , il y a classe C # qui vous permet de voir le nombre absolument exact stocké dans un double. La version en ligne ne fonctionne pas pour le moment - je vais essayer de la mettre sur un autre site.

Etant donné que le débogueur voit le "réel" valeur, il faut faire preuve de discernement sur ce qu'il faut afficher - il peut vous montrer la valeur arrondie à quelques décimales, ou une valeur plus précise. Certains débogueurs lisent mieux que d’autres à la lecture des pensées des développeurs, mais c’est un problème fondamental avec les nombres à virgule flottante binaire.

Utilisez le type decimal à point fixe si vous souhaitez une stabilité aux limites de la précision. Il y a des frais généraux, et vous devez explicitement lancer si vous souhaitez convertir en virgule flottante. Si vous vous convertissez en virgule flottante, vous réintroduisez les instabilités qui semblent vous déranger.

Vous pouvez également vous en sortir et apprendre à utiliser avec la précision limitée de l'arithmétique en virgule flottante. Par exemple, vous pouvez utiliser l'arrondi pour faire converger les valeurs ou utiliser les comparaisons epsilon pour décrire une tolérance. " Epsilon " est une constante que vous avez définie qui définit une tolérance. Par exemple, vous pouvez choisir de considérer que deux valeurs sont égales si elles sont à moins de 0,0001 l'une de l'autre.

Il me semble que vous pourriez utiliser la surcharge d’opérateurs pour rendre les comparaisons epsilon transparentes. Ce serait très cool.

Pour les représentations de mantisse-exposant, EPSILON doit être calculé pour rester dans les limites de la précision représentable. Pour un nombre N, Epsilon = N / 10E + 14

System.Double.Epsilon est la plus petite valeur positive représentable pour le type Double . Il est aussi petit pour notre propos. Lisez les conseils de Microsoft en matière de test d'égalité

J'ai déjà rencontré ce problème auparavant ( sur mon blog ) - Je pense que la surprise est que les chiffres "irrationnels" sont différents.

Par "irrationnel", je parle simplement du fait qu’ils ne peuvent pas être représentés avec précision dans ce format. Les nombres irrationnels réels (tels que & # 960; - pi) ne peuvent pas être représentés avec précision.

La plupart des gens savent qu'un tiers ne travaille pas en décimal: 0.3333333333333 ...

Ce qui est étrange, c’est que 1.1 ne fonctionne pas dans les flottants. Les gens s’attendent à ce que les valeurs décimales fonctionnent en nombres à virgule flottante à cause de la façon dont ils les conçoivent:

  

1.1 est 11 x 10 ^ -1

Quand en réalité ils sont en base 2

  

1.1 est 154811237190861 x 2 ^ -47

Vous ne pouvez pas l'éviter, il vous suffit de vous habituer au fait que certains flottants sont "irrationnels", de la même manière que 1/3.

Pour éviter ce problème, vous pouvez utiliser une bibliothèque utilisant une autre méthode de représentation des nombres décimaux, telle que BCD

Il me semble que 21.399999618530273 est la représentation en simple précision (float) de 21.4. On dirait que le débogueur est en train de descendre du double pour flotter quelque part.

Si vous utilisez Java et que vous avez besoin d’exactitude, utilisez la classe BigDecimal pour les calculs en virgule flottante. Il est plus lent mais plus sûr.

Vous ne pouvez pas éviter cela car vous utilisez des nombres à virgule flottante avec un nombre d'octets fixe. Il n’ya tout simplement pas d’isomorphisme possible entre les nombres réels et leur notation limitée.

Mais la plupart du temps, vous pouvez simplement l'ignorer. 21.4 == 21.4 serait toujours vrai car ce sont toujours les mêmes numéros avec la même erreur. Mais 21.4f == 21.4 peut ne pas être vrai car les erreurs pour float et double sont différentes.

Si vous avez besoin d'une précision fixe, vous devriez peut-être essayer des nombres à points fixes. Ou même des entiers. Par exemple, j’utilise souvent int (1000 * x) pour passer à un pageur de débogage.

Si cela vous dérange, vous pouvez personnaliser le mode d'affichage de certaines valeurs lors du débogage. Utilisez-le avec précaution: -)

Amélioration du débogage avec les attributs d'affichage du débogueur

Consultez la section Arithmétique décimale générale

.

Prenez également note lorsque vous comparez des flottants, voir cette réponse pour plus d'informations.

Selon le javadoc

"Si au moins l'un des opérandes d'un opérateur numérique est de type double, le

    l'opération est effectuée en utilisant une arithmétique à virgule flottante de 64 bits, et le résultat de la commande
    opérateur numérique est une valeur de type double. Si l'autre opérande n'est pas un double, c'est
    premier élargi (& # 167; 5.1.5) pour taper double par promotion numérique (& # 167; 5.6). "

Voici la source

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