Pas vraiment spécifique à l'implémentation de Python mais devrait s'appliquer à toutes les fonctions de chaîne de caractères de float à decimal.
Un nombre à virgule flottante est essentiellement un nombre binaire, mais en notation scientifique avec une limite fixe de chiffres significatifs.
L'inverse de tout nombre dont le facteur est un nombre premier qui n'est pas partagé avec la base donnera toujours une représentation en points récurrents. Par exemple, 1/7 a un facteur premier, 7, qui n'est pas partagé avec 10, et a donc une représentation décimale récurrente, et il en va de même pour 1/10 avec les facteurs premiers 2 et 5, ce dernier n'étant pas partagé avec 2 ; cela signifie que 0,1 ne peut pas être représenté exactement par un nombre fini de bits après le point.
Étant donné que 0,1 n'a pas de représentation exacte, une fonction qui convertit l'approximation en une chaîne de caractères décimaux essaiera généralement d'approximer certaines valeurs afin de ne pas obtenir des résultats peu intuitifs comme 0,1000000000004121.
Comme la virgule flottante est en notation scientifique, toute multiplication par une puissance de la base n'affecte que la partie exposant du nombre. Par exemple, 1.231e+2 * 100 = 1.231e+4 en notation décimale, et de même, 1.00101010e11 * 100 = 1.00101010e101 en notation binaire. Si je multiplie par une non puissance de la base, les chiffres significatifs seront également affectés. Par exemple 1,2e1 * 3 = 3,6e1
Selon l'algorithme utilisé, il peut essayer de deviner les décimales communes en se basant uniquement sur les chiffres significatifs. 0,1 et 0,4 ont tous deux les mêmes chiffres significatifs en binaire, car leurs flottants sont essentiellement des troncatures de (8/5). (2^-4) et (8/5) (2^-6) respectivement. Si l'algorithme identifie le motif sigfig 8/5 comme étant le décimal 1,6, alors il fonctionnera sur 0,1, 0,2, 0,4, 0,8, etc. Il peut également avoir des motifs sigfig magiques pour d'autres combinaisons, comme le flottant 3 divisé par le flottant 10 et d'autres motifs magiques statistiquement susceptibles d'être formés par la division par 10.
Dans le cas de 3*0,1, les derniers chiffres significatifs seront probablement différents de la division d'un flottant 3 par un flottant 10, ce qui fera que l'algorithme ne reconnaîtra pas le nombre magique pour la constante 0,3 en fonction de sa tolérance à la perte de précision.
Edit : https://docs.python.org/3.1/tutorial/floatingpoint.html
Il est intéressant de noter qu'il existe de nombreux nombres décimaux différents qui partagent la même fraction binaire la plus proche. Par exemple, les nombres 0,1, 0,10000000000000001 et 0,1000000000000000055511151231257827021181583404541015625 sont tous approximés par 3602879701896397 / 2 ** 55. Comme toutes ces valeurs décimales partagent la même approximation, n'importe laquelle d'entre elles peut être affichée tout en préservant l'invariant eval(repr(x)) == x.
Il n'y a aucune tolérance pour la perte de précision, si le float x (0.3) n'est pas exactement égal au float y (0.1*3), alors repr(x) n'est pas exactement égal à repr(y).
7 votes
Parce que certains nombres peuvent être représentés exactement, et d'autres non.
59 votes
@MorganThrapp : non, ce n'est pas le cas. Le PO pose une question sur le choix de formatage qui semble plutôt arbitraire. Ni 0,3 ni 0,4 ne peuvent être représentés exactement en virgule flottante binaire.
3 votes
Ce n'est pas du tout arbitraire, ça montre tous les chiffres significatifs.
4 votes
Lien obligatoire sous chaque question relative à la virgule flottante : docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
43 votes
@BartoszKP : Après avoir lu le document plusieurs fois, il n'explique pas pourquoi Python affiche
0.3000000000000000444089209850062616169452667236328125
comme0.30000000000000004
et0.40000000000000002220446049250313080847263336181640625
comme.4
même s'ils semblent avoir la même précision, et ne répond donc pas à la question.6 votes
Voir aussi stackoverflow.com/questions/28935257/ - Je suis un peu irrité qu'il ait été fermé en tant que doublon mais que celui-ci ne l'ait pas été.
3 votes
Gilles Non, il ne s'agit pas d'une duplication de cette question. Il s'agit d'une question sur représentation par chaîne de caractères de points flottants en python .
1 votes
Le bon vieux 2 + 2 = 5 pour les valeurs extrêmement grandes de 2
1 votes
Le site Nouveautés dans la documentation de Python 3.1 (faites défiler jusqu'à la fin de la section liée, juste avant "New, Improved and Deprecated Modules") sont une explication utile pour expliquer pourquoi/quand Python 2.7/3.1+ ont des versions beaucoup plus courtes de
float
repr
pour certaines valeurs. Tout droit sorti de la bouche du cheval, pour ainsi dire.15 votes
Réouvert, s'il vous plaît, ne fermez pas ce sujet comme un doublon de "is floating point math broken" (les maths à virgule flottante sont-elles cassées ?) .