Y a-t-il une signification particulière à 16331239353195370.0?

89

En utilisant import numpy as npj'ai remarqué que

np.tan(np.pi/2)

donne le numéro dans le titre et non np.inf

16331239353195370.0

Je suis curieux de connaître ce nombre. Est-il lié à un paramètre de précision de la machine du système? Aurais-je pu le calculer à partir de quelque chose? (Je pense à quelque chose de similaire à sys.float_info)

EDIT: Le même résultat est en effet reproductible dans d'autres environnements tels que Java, octace, matlab ... La dupe suggérée n'explique cependant pas pourquoi.

Un gars
la source
10
Je n'aime pas cette réponse - elle est entièrement ondulée à la main, n'expliquant pas vraiment la cause. "Eh bien, tan (pi / 2) en radians est essentiellement infini, n'est-ce pas?" n'explique rien sur la raison pour laquelle - comme le PO l'a demandé ici - la réponse n'est pas en fait np.inf. Mais il est simple non seulement d'expliquer pourquoi ce n'est pas le cas, mais aussi d'expliquer pourquoi la réponse est exactement ce qui a été vu - et c'est ce que j'ai fait ;-)
Tim Peters

Réponses:

119

pin'est pas exactement représentable en tant que flotteur Python (identique au type de la plate-forme C double). L'approximation représentable la plus proche est utilisée.

Voici l'approximation exacte utilisée sur ma box (probablement la même que sur votre box):

>>> import math
>>> (math.pi / 2).as_integer_ratio()
(884279719003555, 562949953421312)

Pour trouver la tangente de ce rapport, je vais maintenant passer à wxMaxima:

(%i1) fpprec: 32;
(%o1) 32
(%i2) tan(bfloat(884279719003555) / 562949953421312);
(%o2) 1.6331239353195369755967737041529b16

Donc essentiellement identique à ce que vous avez. L'approximation binaire pi/2utilisée est un peu inférieure à la valeur mathématique ("précision infinie") de pi/2. Vous obtenez donc une très grande tangente au lieu de infinity. Le calcul tan()est approprié pour l'entrée réelle!

Pour exactement les mêmes types de raisons, par exemple,

>>> math.sin(math.pi)
1.2246467991473532e-16

ne renvoie pas 0. L'approximation math.piest un peu inférieure à pi, et le résultat affiché est correct étant donné cette vérité.

AUTRES FAÇONS DE VOIR math.pi

Il existe plusieurs façons de voir l'approximation exacte utilisée:

>>> import math
>>> math.pi.as_integer_ratio()
(884279719003555, 281474976710656)

math.pi est exactement égale à la valeur mathématique ("précision infinie") de ce rapport.

Ou comme un flottant exact en notation hexadécimale:

>>> math.pi.hex()
'0x1.921fb54442d18p+1'

Ou d'une manière la plus facilement comprise par à peu près tout le monde:

>>> import decimal
>>> decimal.Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

Bien que cela ne soit pas immédiatement évident, chaque flottant binaire fini est exactement représentable comme un flottant décimal fini (l'inverse n'est pas vrai; par exemple, le décimal 0.1n'est pas exactement représentable comme un flottant binaire fini), et le Decimal(some_float)constructeur produit l'équivalent exact.

Voici la vraie valeur de pisuivie de la valeur décimale exacte de math.pi, et un signe d'insertion sur la troisième ligne pointe vers le premier chiffre où ils diffèrent:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.piest le même dans «presque toutes» les boîtes maintenant, parce que presque toutes les boîtes utilisent maintenant le même format binaire à virgule flottante (IEEE 754 double précision). Vous pouvez utiliser l'une des méthodes ci-dessus pour confirmer cela sur votre boîte, ou pour trouver l'approximation précise utilisée si votre boîte est une exception.

Tim Peters
la source
@Tim Peters - C'est parfaitement clair. Par souci d'exhaustivité, je suppose que cette représentation de np.piest la représentation rationnelle la plus proche de l'epsilon du système?
Aguy du
3
En supposant qu'il np.pia la même valeur que celle de Python math.pi(je n'ai pas vérifié, mais vous pouvez ;-)), c'est la valeur la plus proche du pi mathématique représentable dans le C doubleformat flottant natif de la plate-forme. Ce qui signifie la double précision IEEE 754 sur presque toutes les boîtes maintenant, et donc le flotteur binaire le plus proche avec 53 bits de précision (mantisse). Ainsi, l'ensemble des rationnels est contraint à la forme +/- I * 2**Joù l'entier Ivaut 0 ou 2**52 <= I < 2**53, et la plage des entiers Jest suffisamment large pour couvrir tous les rationnels de cette forme n'importe où pi.
Tim Peters du
2
Et voilà pourquoi je l' aime si « binaires » fonctions trigonométriques étaient plus souvent mises en œuvre. Puisque pi ne peut jamais être représenté dans un rationnel, il serait pratique avec un ensemble de fonctions opérant sur des angles de 0 à 1.
pipe
Eh bien, ils ont importé np.pi, non math.pi.
EKons du
2
@ Έρικ Κωνσταντόπουλος math.pi, np.piet scipy.pisont tous identiques; ils sont dupliqués juste pour faciliter la dénomination; stackoverflow.com/questions/12645547/…
Tim Peters