2010-01-17 11 views
0

Doublons possibles:
Why is floating point arithmetic in C# imprecise?
Why does ghci say that 1.1 + 1.1 + 1.1 > 3.3 is True?Pourquoi ne reçois-je pas zéro lorsque je soustrais le même nombre à virgule flottante de lui-même dans Perl?

#!/usr/bin/perl 
$l1 = "0+0.590580+0.583742+0.579787+0.564928+0.504538+0.459805+0.433273+0.384211+0.3035810"; 
$l2 = "0+0.590580+0.583742+0.579788+0.564928+0.504538+0.459805+0.433272+0.384211+0.3035810"; 
$val1 = eval ($l1); 
$val2 = eval ($l2); 
$diff = (($val1 - $val2)/$val1)*100; 
print " (($val1 - $val2)/$val1)*100 ==> $diff\n"; 

Étonnamment, la sortie a fini par être

((4.404445 - 4.404445)/4.404445)*100 ==> -2.01655014354845e-14. 

est-il pas censé être un ZERO ???? Quelqu'un peut-il expliquer cela s'il vous plaît ......

+2

Quoi, vous ne pensez pas que 0.000000000000201655014354845 est assez proche de zéro? – Ether

+0

Cette question n'est pas complètement un doublon des questions non-perl citées parce que la question est compliquée par perl fournissant une précision de stringification par défaut légèrement inférieure à la précision numérique disponible. – ysth

Répondre

7

Il est assez proche de zéro, ce qui est ce que je m'attendais.

Pourquoi est-ce censé être zéro? 0,579787! = 0,579788 et 0,433273! = 0,433272. Il est probable qu'aucun d'entre eux n'ait une représentation exacte en virgule flottante, vous devriez donc vous attendre à des inexactitudes.

3

Lorsque vous modifiez les deux chaînes pour qu'elles soient égales (il y a 2 chiffres différents entre $l1 et $l2), il en résulte effectivement zéro. Ce qui est démontré, c'est que vous pouvez créer 2 nombres à virgule flottante différents ($val1 et $val2) qui ont la même apparence à l'impression, mais qui ont une petite différence en interne. Ces différences peuvent être amplifiées si vous ne faites pas attention.

Vinko Vrsalovic a posté de bons liens pour expliquer pourquoi.

4

De la réponse de perlfaq4 à Why am I getting long decimals (eg, 19.9499999999999) instead of the numbers I should be getting (eg, 19.95)?:


En interne, votre ordinateur représente des nombres à virgule flottante en binaire. Les ordinateurs numériques (comme les puissances de deux) ne peuvent pas stocker tous les nombres exactement. Certains nombres réels perdent de la précision dans le processus. C'est un problème avec la façon dont les ordinateurs stockent des nombres et affecte tous les langages informatiques, pas seulement Perl.

perlnumber montre les détails sanglants des représentations numériques et des conversions.

Pour limiter le nombre de décimales dans vos nombres, vous pouvez utiliser la fonction printf ou sprintf. Voir le "Floating Point Arithmetic" pour plus de détails.

printf "%.2f", 10/3; 

my $number = sprintf "%.2f", 10/3; 
+0

C'est un peu le revers de cette perlfaq; voir mon commentaire à la question. – ysth