2 votes

Numpy : précision des points décimaux des nombres complexes

Considérons le code Python suivant qui effectue quelques opérations arithmétiques simples sur des nombres complexes en Python :

import numpy as np

s = 2
l = 5
v = np.array([np.exp(1j*2*np.pi/l)])
A = pow(s*v, l) + s*v

#Print the precision of np.complex128
print np.finfo(np.complex128).precision

#Export using 20 decimal places for real and imaginary parts
np.savetxt('A.csv', A, fmt=['%.20e%+.20ej'], delimiter=',')

J'ai vu ça réponse afin d'imprimer la précision d'un np.complex128 en Python et ce que j'obtiens est 15. Lorsque je vérifie la valeur de A dans Spyder, je constate que (32.61803398874989+1.9021130325903035j) dont la partie imaginaire a plus de 15 décimales. De plus, le fichier CSV exporté a la valeur 3.26180339887498931262e+01+1.90211303259030350965e+00j dont les parties réelles et imaginaires ont 20 utile décimales.

Je ne comprends pas bien : si la précision est de 15, à quoi correspondent ces décimales supplémentaires ? D'après aquí , np.complex128 consiste en deux flottants de 64 bits, un pour la partie réelle et un pour la partie imaginaire.

Mais mon principal problème est que j'effectue un grand nombre de ces opérations sur des nombres complexes (comme des additions, des multiplications et des inversions de matrices) dans un programme et, à chaque fois, j'obtiens un résultat différent, parfois correct, parfois faux. Il semble que mon programme soit très sensible à la précision de ces opérations. Comment la précision sur les nombres complexes est-elle quantifiée en Python et quel est le maximum que je peux avoir ?

J'utilise Python 2.7.14 et Numpy 1.14.3.

1voto

Rory Daulton Points 11787

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.

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