web-dev-qa-db-fra.com

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

En utilisant import numpy as np J'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-ce lié à un paramètre de précision de la machine 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 ... Le dupe suggéré n'explique cependant pas pourquoi.

87
Aguy

pi n'est pas exactement représentable comme Python float (identique au type double de la plate-forme C). L'approximation représentable la plus proche est utilisée.

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

>>> 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 obtenu. L'approximation binaire de pi/2 Utilisée est légèrement inférieure à la valeur mathématique ("précision infinie") de pi/2. Vous obtenez donc une très grande tangente au lieu de infinity. La tan() calculée est appropriée 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.pi est un peu inférieure à pi, et le résultat affiché est correct 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 égal à la valeur mathématique ("précision infinie") de ce rapport.

Ou comme un flotteur exact en notation hexadécimale:

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

Ou d'une manière plus facilement compréhensible 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 est pas vrai; par exemple, le 0.1 Décimal n'est pas exactement représentable comme un flottant décimal flottant binaire), et le constructeur Decimal(some_float) produit l'équivalent exact.

Voici la vraie valeur de pi suivie 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.pi Est désormais le même pour "presque toutes" les boîtes, car presque toutes les boîtes utilisent désormais le même format binaire à virgule flottante (double précision IEEE 754). Vous pouvez utiliser l'une des méthodes ci-dessus pour confirmer que sur votre boîte, ou pour trouver l'approximation précise utilisée si votre boîte est une exception.

117
Tim Peters