Une réponse complète prendrait beaucoup de place. Pour commencer, vous devriez lire un livre sur l'analyse numérique qui explique comment les types binaires à virgule flottante fonctionnent et sont stockés. Mais voici quelques explications partielles.
Les valeurs flottantes de 64 bits sont stockées en binaire, et non en décimal. Ainsi, la plupart de ce qui est dit sur les chiffres décimaux doit être une approximation, et non l'histoire complète.
Lorsque np.finfo(np.complex128).precision
(ou autre) dit qu'il y a 15 chiffres décimaux significatifs, cela signifie que vous ne pouvez pas compter sur plus que ces 15 chiffres. Voici un exemple, tiré de ma console IPython.
In [4]: 9.000000000000001
Out[4]: 9.000000000000002
In [5]: 9.000000000000001 == 9.000000000000002
Out[5]: True
Python, qui utilise par défaut le type de virgule flottante 64 bits pour tout nombre comportant une virgule décimale, traite ces deux nombres à 16 chiffres décimaux comme identiques. Lorsque vous utilisez le nombre 9.000000000000001
seuls les 15 premiers chiffres décimaux sont garantis d'être stockés correctement. Tout ce qui se trouve après n'est pas garanti, et vous voyez dans ce cas l'icône 1
est essentiellement transformé en un 2
.
Parfois, vous pouvez obtenir plus que ces 15 chiffres décimaux. Par exemple, étant donné que les nombres sont stockés en binaire, un nombre légèrement supérieur à 1.0
aura plus de chiffres binaires après le point radix qu'un nombre comme 9.0
volonté. Cela est dû au fait que 9
utilise 4 chiffres binaires tandis que 1
n'en utilise qu'un seul, de sorte que 3 chiffres binaires supplémentaires peuvent être utilisés après le point de radix. Examinons donc la partie imaginaire de votre nombre, 1.9021130325903035
:
In [17]: 1.902113032590303 == 1.9021130325903035
Out[17]: False
In [18]: 1.9021130325903036 == 1.9021130325903035
Out[18]: True
In [19]: 1.902113032590304 == 1.9021130325903035
Out[19]: False
Nous voyons que, bien que le nombre présente 17 chiffres décimaux, lorsque nous changeons le dernier chiffre de 5 à 6, Python ne voit aucun changement. Mais il y a un changement si nous arrondissons ce nombre à 16 chiffres décimaux, que ce soit vers le haut ou vers le bas. Nous pouvons donc dire que le nombre est stocké à 16 chiffres décimaux et un peu plus. C'est pourquoi, lorsque j'explique la précision, je dis qu'un nombre à virgule flottante est garanti avec 15 chiffres décimaux significatifs, mais qu'il peut en avoir un 16e, et que la précision réelle est légèrement supérieure à cela. Plus brièvement, il y a 15 ou 16 chiffres décimaux significatifs.
Python dispose de deux méthodes de base pour imprimer un nombre à virgule flottante : la fonction str
et la fonction repr
fonction. Le site str
imprime les choses simplement, de sorte que l'utilisateur puisse comprendre le résultat sans entrer dans trop de détails. Le site repr
donne plus de détails, et essaie d'imprimer tellement de détails que les données stockées peuvent être complètement déterminées par ce qui est imprimé. Notez que repr
est utilisé de manière invisible dans certains cas, comme la saisie d'une valeur numérique dans la console ou, comme vous l'avez vu, l'utilisation de l'explorateur de variables dans Spyder.
Lorsque Spyder ou Python fait un repr
sur votre numéro 1.9021130325903035
il donne suffisamment de chiffres pour définir complètement le nombre. Comme nous l'avons vu plus haut, s'il n'y avait que 16 chiffres décimaux, il suffirait d'enlever le dernier chiffre. 5
le résultat serait légèrement différent de ce qui est stocké. C'est pourquoi Python imprime un chiffre supplémentaire afin que vous puissiez savoir exactement quelle est la valeur. Si Python imprimait un dernier 6
plutôt qu'un 5
la valeur aurait été la même, mais si Python omettait complètement ce chiffre, la valeur serait modifiée. Python utilise donc repr
se trompe en donnant trop de chiffres. Malgré les 17 chiffres imprimés, seuls 16 d'entre eux sont certains.
Enfin, votre fichier csv affiche 20 chiffres décimaux parce que vous avez demandé à Python d'afficher 20 chiffres décimaux, en raison de l'attribut %.20e
dans votre np.savetxt
commandement. Ces 20 chiffres décimaux ne sont pas tous " utile décimales", malgré ce que vous avez écrit. Seuls les 16 ou 17 premiers sont utiles dans la partie imaginaire, selon la façon dont vous définissez "utile". Python a fondamentalement ajouté des bits binaires, tous des zéros, à la valeur stockée, et a imprimé cela à 20 chiffres décimaux. Mais ces bits binaires nuls n'étaient pas stockés dans la valeur.