29 votes

Exemples d'inexactitude en virgule flottante

Comment expliquez-vous l'inexactitude en virgule flottante aux nouveaux programmeurs et profanes qui pensent toujours que les ordinateurs sont infiniment sages et précis?
Avez-vous un exemple ou une anecdote préférée qui semble faire passer l'idée bien mieux qu'une explication précise, mais sèche?
Comment est-ce enseigné dans les cours d'informatique?

26voto

Joey Points 148544

Il existe essentiellement deux grands écueils gens trébuchent avec des nombres à virgule flottante.

  1. Le problème de l'échelle. Chaque FP nombre a un exposant qui détermine l'ensemble de "l'échelle" de la le nombre de sorte que vous pouvez représenter soit vraiment des valeurs petites ou très grandes, même si le nombre de chiffres que vous pouvez consacrer pour qui est limité. Ajouter deux nombres différents à l'échelle entraîne parfois la plus petite "mangé" car il n'existe aucun moyen de le tenir dans la 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
    

    Comme une analogie pour ce cas, vous pourriez l'image d'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 combien ils sont à peu près. Verser la cuillère à café dans la piscine, cependant, vous laissera toujours avec près d'une piscine pleine d'eau.

    (Si les gens l'apprentissage de cette ont de la difficulté avec la notation exponentielle, on peut aussi utiliser les valeurs 1 et 100000000000000000000 ou plus.)

  2. Il y a ensuite le problème de la binaire vs représentation décimale. Un certain nombre comme 0.1 ne peut pas être représenté exactement avec un nombre limité de chiffres binaires. Certaines langues masque de cela, si:

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

    Mais vous pouvez "amplifier" la représentation de l'erreur par l'ajout répété de ces chiffres:

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

    Je ne peux pas penser à une belle analogie pour expliquer correctement ce, bien que. C'est essentiellement le même problème, pourquoi vous pouvez représenter 1/3 seulement environ en décimal parce que pour obtenir la valeur exacte vous devez répéter les 3 indéfiniment à la fin de la fraction décimale.

    De même, binaire fractions sont bonnes pour la représentation des moitiés, quarts, huitièmes, etc. mais des choses comme un dixième donnera une infinie répétition de flux de chiffres binaires.

  3. Ensuite, il y a un autre problème, bien que la plupart des gens à ne pas tomber dans que, si elles ne font d'énormes quantités de numérique choses. Mais alors, ceux qui le connaissent déjà le problème. Depuis de nombreuses nombres à virgule flottante sont seulement des approximations de la valeur exacte, cela signifie que pour un rapprochement f d'un nombre réel r , il peut être infiniment beaucoup plus de nombres réels r1, r2, ... de la carte à exactement le même rapprochement. Ces chiffres se situent dans un certain intervalle. Disons que rmin est la valeur minimum possible de r que les résultats de f et rmax au maximum la valeur de r pour laquelle cela est, alors vous avez obtenu un intervalle [rmin, rmax] où n'importe quel nombre dans cet intervalle peut être votre nombre réel r.

    Maintenant, si vous effectuer des calculs sur le nombre-l'addition, la soustraction, la multiplication, etc.-vous perdez en précision. Chaque numéro est seulement une approximation, par conséquent, vous êtes en fait effectuer des calculs avec des intervalles. Le résultat est un intervalle trop et l'erreur d'approximation seulement devient plus grande, ce qui, en élargissant l'intervalle. Vous pouvez obtenir un numéro unique à partir de ce calcul. Mais c'est simplement un nombre de l'intervalle de possible de résultats, en tenant compte de la précision de l'original de votre opérandes et la perte de précision due en raison du calcul.

    Ce genre de chose s'appelle l'arithmétique d'Intervalle, et au moins pour moi, c'était une partie de nos cours de mathématiques à l'université.

8voto

Joachim Sauer Points 133411

Montrer que la base 10 système souffre exactement du même problème.

Essayer de représenter 1/3 comme une 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 assez exacte de la représentation pour de nombreux cas d'utilisation.

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

D'autres fractions, comme 1/2 peut facilement être représenté par un nombre fini de décimales de la représentation en base 10: "0.5"

Maintenant en base 2 et en base 10 en souffrent essentiellement le même problème: les deux ont quelques numéros qu'ils ne peuvent pas représenter exactement.

Alors qu'en base 10 n'a pas de problème, représentant 1/10 comme "0.1" en base 2, vous auriez besoin d'une infinie représentation en commençant par "0.000110011..".

6voto

gary Points 426

Comment est-ce pour une explantation pour le profane. Une façon ordinateurs représenter des nombres est de compter les unités discrètes. Ce sont des ordinateurs numériques. Pour les nombres entiers, les sans-partie fractionnaire, numérique moderne ordinateurs compter les puissances de deux: 1, 2, 4, 8. ,,, La valeur de la Place, de chiffres binaires, blah , blah, blah. Pour les fractions, les ordinateurs numériques, comte inverse des puissances de deux: 1/2, 1/4, 1/8, ... Le problème est que de nombreux numéros ne peuvent pas être représentés par une somme d'un nombre fini de ces inverse pouvoirs. À l'aide des valeurs de plus en plus de place (plus de bits) va augmenter la précision de la représentation de ces "problème" des nombres, mais jamais il exactement car il ne dispose que d'un nombre limité de bits. Certains numéros ne peuvent pas être représentés avec un nombre infini de bits.

Sieste...

OK, vous voulez mesurer le volume de l'eau dans un récipient, et vous n'avez que 3 tasses de mesure: coupe pleine, demi-tasse et quart de tasse. Après le décompte de la dernière coupe pleine, disons qu'il y a un tiers d'une tasse restante. Pourtant, vous ne pouvez pas mesurer ce que parce qu'il ne correspond pas exactement à remplir n'importe quelle combinaison de disponible tasses. Il ne remplit pas le demi-tasse, et le débordement du quart de tasse est trop petite pour remplir quoi que ce soit. Si vous avez une erreur - la différence entre 1/3 et 1/4. Cette erreur est aggravé lorsque vous le combinez avec des erreurs à partir d'autres mesures.

2voto

codeape Points 38576

En python:

 >>> 1.0 / 10
0.10000000000000001
 

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

2voto

cibercitizen1 Points 3093

Un autre exemple, en C

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

donne incroyablement

3.60000000000000008882

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X