Question

Comment expliquez-vous l'inexactitude flottante point de nouveaux programmeurs et laïcs qui pensent encore les ordinateurs sont infiniment sage et précis?
Avez-vous un exemple préféré ou une anecdote qui semble faire passer l'idée bien mieux qu'un précis, mais sec, explication?
Comment cela est enseigné dans les cours de sciences informatiques?

Était-ce utile?

La solution

Il existe essentiellement deux grands pièges gens trébuchent avec nombres à virgule flottante.

  1. Le problème d'échelle. Chaque numéro FP a un exposant qui détermine la « échelle » globale du nombre de sorte que vous pouvez représenter soit des valeurs très petites ou celles qui sont vraiment larges, bien que le nombre de chiffres que vous pouvez consacrer à cela est limité. Ajout de deux nombres de différentes échelles se traduira parfois dans le plus petit être « mangé » car il n'y a aucun moyen de l'adapter à plus grande échelle.

    PS> $a = 1; $b = 0.0000000000000000000000001
    PS> Write-Host a=$a b=$b
    a=1 b=1E-25
    PS> $a + $b
    1
    

    Par analogie pour ce cas, vous pouvez imaginer une grande piscine et une cuillère à café d'eau. Les deux sont de tailles très différentes, mais individuellement vous pouvez facilement saisir à quel point ils sont à peu près. Cependant, verser la cuillère à café dans la piscine, vous laissera toujours avec à peu près d'une piscine d'eau.

    (Si les gens ont du mal à apprendre ce avec la notation exponentielle, on peut aussi utiliser les valeurs 1 et 100000000000000000000 environ.)

  2. Ensuite, il y a le problème de binaire par rapport à la représentation décimale. Un certain nombre comme 0.1 ne peut pas être représenté exactement avec une quantité limitée de chiffres binaires. Certaines langues masquent cela, cependant:

    PS> "{0:N50}" -f 0.1
    0.10000000000000000000000000000000000000000000000000
    

    Mais vous pouvez « amplifier » l'erreur de représentation en ajoutant à plusieurs reprises les chiffres ainsi:

    PS> $sum = 0; for ($i = 0; $i -lt 100; $i++) { $sum += 0.1 }; $sum
    9,99999999999998
    

    Je ne peux pas penser à une analogie agréable pour bien expliquer cela, cependant. Il est fondamentalement le même problème pourquoi vous pouvez représenter 1 / 3 qu'approximativement en décimal parce que pour obtenir la valeur exacte que vous devez répéter 3 indéfiniment à la fin de la fraction décimale .

    De même, les fractions binaires sont bonnes pour représenter moitiés, quartiers, etc., mais croches des choses comme un dixième donnera un flux continu de répétition de chiffres binaires.

  3. Ensuite, il y a un autre problème, bien que la plupart des gens ne trébuchent pas dans ce, à moins qu'ils font d'énormes quantités de choses numériques. Mais alors, ceux qui connaissent déjà le problème. Étant donné que beaucoup de nombres à virgule flottante ne sont que des approximations de la valeur exacte, cela signifie que pour une approximation donnée f d'un nombre réel r il peut y avoir une infinité de nombres plus réels r 1 , r 2 , ... quelle carte exactement la même approximation. Ces chiffres se situent dans un certain intervalle. Disons que r min est la valeur minimale possible de r que les résultats dans f et r max la valeur maximale possible de r pour lequel cela vaut, alors vous avez un intervalle [ r min , r max ] où un nombre dans cet intervalle peut être votre nombre réel r .

    Maintenant, si vous effectuez des calculs sur ce nombre-addition, la soustraction, la multiplication, etc., vous perdez précision. Chaque numéro est juste une approximation, par conséquent, vous êtes en train de réaliser des calculs avec des intervalles . Le résultat est un intervalle trop et l'erreur d'approximation que jamais grossit, élargissant ainsi l'intervalle. Vous pouvez récupérer un seul numéro de ce calcul. Mais c'est simplement un Numéro de l'intervalle de possibles résultats, en prenant en précision compte de vos opérandes d'origine et la perte de précision en raison du calcul.

    Ce genre de chose est appelé Intervalle arithmétique et au moins pour moi que cela faisait partie de notre cours de mathématiques à l'université.

Autres conseils

Montrez que le système de base 10 souffre de exactement le même problème.

Essayez de représenter un tiers en tant que représentation décimale en base 10. Vous ne serez pas en mesure de le faire exactement.

Donc, si vous écrivez « 0,3333 », vous aurez une représentation raisonnablement exacte pour de nombreux cas d'utilisation.

Mais si vous déplacez ce retour à une fraction, vous obtiendrez "3333/10000", qui est pas la même chose que "1/3".

D'autres fractions, comme 1/2 peuvent facilement être représentés par une représentation décimale finie en base-10: « 0,5 »

base 2 et base 10 souffrent d'essentiellement le même problème: les deux ont des chiffres qu'ils ne peuvent pas représenter exactement

.

Alors que la base-10 n'a pas de problème représentant 1/10 que « 0,1 » en vous base 2 auriez besoin d'une représentation infinie commençant par « 0,000110011 .. ».

Comment est ce pour une explantation pour le profane. Un façon dont les ordinateurs représentent des nombres est en comptant des unités discrètes. Ce sont des ordinateurs numériques. Pour des nombres entiers, les personnes sans partie fractionnaire, les ordinateurs numériques modernes comptent des puissances de deux: 1, 2, 4, 8. ,,, valeur Place, chiffres binaires, bla, bla, bla. Pour les fractions, les ordinateurs numériques comptent puissances inverses de deux: 1/2, 1/4, 1/8, ... Le problème est que beaucoup de chiffres ne peuvent pas être représentés par une somme d'un nombre fini de ces puissances inverses. En utilisant plus de valeurs de position (plus de bits) augmentera la précision de la représentation de ces chiffres « problème », mais jamais exactement parce qu'il a un nombre limité de bits. Certains numéros ne peuvent pas être représentés par un nombre infini de bits.

Snooze ...

OK, vous voulez mesurer le volume d'eau dans un récipient, et vous avez seulement 3 tasses de mesure: tasse pleine, demi-tasse et quart de tasse. Après avoir compté la dernière coupe pleine, disons il y a un tiers d'une tasse restante. Pourtant, vous ne pouvez pas mesurer cela parce qu'il ne remplit pas exactement une combinaison de tasses disponibles. Il ne remplit pas la coupe de moitié, et le trop-plein de la coupe du quart est trop faible pour remplir quoi que ce soit. Donc, vous avez une erreur - la différence entre 1/3 et 1/4. Cette erreur est aggravée lorsque vous combinez avec des erreurs d'autres mesures.

En python:

>>> 1.0 / 10
0.10000000000000001

Expliquez comment certaines fractions ne peuvent pas être représentés avec précision en binaire. Tout comme certaines fractions (comme 1/3) ne peuvent pas être représentées exactement en base 10.

Un autre exemple, dans C

printf (" %.20f \n", 3.6);

donne incroyablement

3,60000000000000008882

Voici ma compréhension simple.

Problème: La valeur 0,45 ne peut pas être représenté exactement par un flotteur et est arrondie à 0,450000018. Pourquoi?

Réponse: Une valeur d'int 45 est représenté par la valeur binaire 101101. Afin de rendre la valeur 0.45, il serait exact si vous pouvez prendre 45 x 10 ^ -2 (= 45/10 ^ 2.) Mais cela est impossible parce que vous devez utiliser la base 2 au lieu de 10.

le plus proche de 10 ^ 2 = 100 serait 128 = 2 ^ 7. Le nombre total de bits nécessaires est de 9: 6 pour la valeur 45 (101101) + 3 bits pour la valeur 7 (111). Ensuite, la valeur 45 x 2 ^ -7 = 0,3515625. Maintenant, vous avez un problème d'inexactitude grave. 0.3515625 est loin d'être proche de 0,45.

Comment améliorer cette inexactitude? Eh bien, nous pourrions changer la valeur 45 et 7 à autre chose.

Comment environ 460 x 2 ^ -10 = 0,44921875. Vous utilisez maintenant 9 bits pour 460 et 4 bits pour 10. Ensuite, il est un peu plus près, mais toujours pas proche. Toutefois, si votre valeur initiale souhaitée est 0,44921875 alors vous obtenez une correspondance exacte sans approximation.

Ainsi, la formule de votre valeur serait X = A x 2 ^ B. Où A et B sont des valeurs entières positives ou négatives. Il est évident que plus les chiffres peuvent être le plus élevé serait votre précision cependant devenu comme vous le savez le nombre de bits pour représenter les valeurs A et B sont limitées. Pour Float vous avez un nombre total de 32. Double a 64 et décimal a 128.

Un morceau mignon de bizarrerie numérique peut être observée si l'on convertit 9999999,4999999999 à un float et de retour à un double. Le résultat est rapporté comme 10000000, même si cette valeur est évidemment plus proche de 9.999.999, et même si 9999999,499999999 arrondit correctement 9.999.999.

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