Pourquoi la boucle for utilisant un double échoue-t-elle à se terminer

Je regarde à travers les anciennes questions d'examen (actuellement première année d'uni.) et je me demande si quelqu'un pourrait expliquer un peu plus en profondeur pourquoi la boucle for suivante ne se termine pas quand elle est supposée le faire. Pourquoi est-ce arrivé? Je comprends qu'il saute 100.0 à cause d'une erreur d'arrondi ou quelque chose, mais pourquoi?

for(double i = 0.0; i != 100; i = i +0.1){
    System.out.println(i);
}
27
demandé sur Raedwald 2013-11-11 17:07:25

5 réponses

Le nombre 0.1 ne peut pas être exactement représenté en binaire, tout comme 1/3 ne peut pas être exactement représenté en décimal, en tant que tel, vous ne pouvez pas garantir que:

0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1==1

C'est parce que dans binaire:

0.1=(binary)0.00011001100110011001100110011001....... forever

Cependant un double ne peut pas contenir une précision infinie et ainsi, tout comme nous approchons 1/3 à 0.3333333 de même la représentation binaire doit se rapprocher de 0.1.


Analogie décimale élargie

En décimal, vous pouvez trouver que

1/3+1/3+1/3
=0.333+0.333+0.333
=0.999

, C'est exactement le même problème. Cela ne devrait pas être considéré comme une faiblesse des nombres à virgule flottante car notre propre système décimal a les mêmes difficultés (mais pour des nombres différents, quelqu'un avec un système de base-3 trouverait étrange que nous ayons du mal à représenter 1/3). C'est cependant un problème à prendre en compte.

Démo

Une démo en direct fournie par Andrea Ligios montre ces erreurs qui s'accumulent.

42
répondu Richard Tingle 2013-11-11 16:51:20

Les ordinateurs (au moins actuels) fonctionnent avec des données binaires. De plus, il existe une limitation de longueur pour les ordinateurs à traiter dans leurs unités logiques arithmétiques (c'est-à-dire 32 bits, 64 bits, etc.). Représenter des entiers sous forme binaire est simple au contraire nous ne pouvons pas dire la même chose pour les points flottants. Représentation en virgule flottante 64 bits

Comme indiqué ci-dessus, il existe une façon particulière de représenter les points flottants selon IEEE-754 qui est également acceptée de facto par les producteurs de processeurs et les logiciels est important pour tout le monde de le savoir.

Si nous regardons la valeur maximale d'un double en java (Double.MAX_VALUE) est 1. 7976931348623157E308 (>10^307). seulement avec 64 bits, des nombres énormes pourraient être représentés mais le problème est la précision.

Comme '==' et '!= 'les opérateurs comparent les nombres bit à bit, dans votre cas 0.1+0.1+0.1 n'est pas égal à 0,3 en termes de bits qu'ils sont représentés.

En conclusion, pour adapter d'énormes nombres à virgule flottante en quelques bits intelligents les ingénieurs ont décidé de sacrifier la précision. Si vous travaillez sur des points flottants, vous ne devriez pas utiliser '==' ou '!=' sauf si vous êtes sûr de ce que vous faites.

11
répondu hevi 2013-11-15 07:24:22

En règle générale, n'utilisez jamais double pour itérer en raison d'erreurs d'arrondi (0.1 peut sembler agréable lorsqu'il est écrit en base 10, mais essayez de l'écrire en base 2-ce que double utilise). Ce que vous devriez faire est d'utiliser une variable int simple pour itérer et calculer le double à partir de celle-ci.

for (int i = 0; i < 1000; i++)
  System.out.println(i/10.0);
10
répondu Marko Topolnik 2013-11-11 13:17:16

Tout d'abord, je vais vous expliquer certaines choses sur les doubles. Cela aura effectivement lieu dans la base dix pour faciliter la compréhension.

Prenez la valeur d'un tiers et essayez de l'exprimer en base dix. Vous obtenez 0.333333333333333.... Disons que nous devons l'arrondir à 4 endroits. Nous obtenons 0,3333. Maintenant, ajoutons un autre 1/3. Nous obtenons 0.6666333333333.... qui arrondit à 0.6666. Ajoutons un autre 1/3. Nous obtenons 0.9999, pas 1.

La même chose se produit avec la base deux et un dixième. Depuis vous allez par 0.110 et 0.110 est la répétition d'une valeur binaire(comme 0.1666666... en base dix), vous aurez juste assez d'erreur pour manquer cent quand vous y arrivez.

1/2 peut être représenté en base dix très bien, et 1/5 peut aussi bien. C'est parce que les facteurs premiers du dénominateur sont un sous-ensemble des facteurs de la base. Ce n'est pas le cas pour un tiers dans la base dix ou un dixième dans la base deux.

8
répondu Andrey Akhmetov 2013-11-11 19:41:55

, Il devrait être pour(double a = 0.0; un

Essayez de voir si cela fonctionne à la place

0
répondu 2013-11-15 15:43:53