Parfois, les limitations de l’ordinateur se font sentir. Exemple à la con:
Je fais une somme sur une liste de nombres réels. Suivant l’ordre dans lequel l’ordinateur additionne les nombres, il donne un résultat « légèrement » différent.
#!/usr/bin/python
values = [76923076923, 1428.5714285714284, 1250000.0, 8333.333333333332, 125000000.0, 7142857.142857143]
sorted_values = sorted(values)
print "sum", sum(values)
print "sum sorted", sum(sorted_values)
print "equality", sum(values) == sum(sorted_values)
print "difference", sum(sorted_values) - sum(values)
sum 77056479542.0
sum sorted 77056479542.0
equality False
difference 1.52587890625e-05
C’est bien sûr du à la manière dont sont stockés et manipulés les nombres réels sur un ordinateur. Ici, en nombre à virgule flottante sur 64bits. Le problème se reproduit dans d’autres langages.
C’est plutôt gênant quand on fait du multithreading car on s’attend à ce que l’addition de données en provenance désordonnée de plusieurs threads donne la même chose que l’addition de données provenant d’un seul thread. Mais non, il faut prendre ses précautions.
Je me suis fait avoir récemment, c’est le cercle 1 du fameux R inferno http://www.burns-stat.com/pages/Tutor/R_inferno.pdf
Suffit de prendre un bon langage, comme Perl6 :-D
« `
#!/usr/bin/env perl6
my @values = 76923076923, 1428.5714285714284, 1250000.0, 8333.333333333332, 125000000.0, 7142857.142857143;
my @sorted_values = @values.sort;
my ($sum, $sum_sorted) = (0, 0);
for @values -> $num {
$sum += $num;
}
for @sorted_values -> $num {
$sum_sorted += $num;
}
say « sum » ~ $sum;
say « sum sorted » ~ $sum_sorted;
say « equality » ~ ($sum == $sum_sorted);
say « difference » ~ ($sum_sorted – $sum);
« `
La sortie :
« `
sum 77056479542.0476190477604
sum sorted 77056479542.0476190477604
equality True
difference 0
« `
Enjoy :-)
Ou d’utiliser les bons outils :
En python 3.5 -> https://docs.python.org/3/whatsnew/3.5.html#pep-485-a-function-for-testing-approximate-equality
J’ai écrit l’exemple en Python pour faire simple. Le problème se pose aussi en C++.
D’ailleurs, les modules comme Decimal en Python, ils sont implémentés comment? Avec des entiers? Je suppose que la performance en prend un coup?
même avec le module Decimal:
Decimal(« 1 ») / Decimal(« 3 ») * Decimal(« 3 ») != Decimal(« 1 »)
Qu’en dit perl6 ?