Hat 16331239353195370.0 eine besondere Bedeutung?

88

Mit import numpy as nphabe ich das bemerkt

np.tan(np.pi/2)

gibt die Nummer im Titel an und nicht np.inf

16331239353195370.0

Ich bin neugierig auf diese Nummer. Bezieht es sich auf einen Präzisionsparameter der Systemmaschine? Könnte ich es aus etwas berechnet haben? (Ich denke nach dem Vorbild von etwas ähnlichem sys.float_info)

BEARBEITEN: Das gleiche Ergebnis ist in der Tat in anderen Umgebungen wie Java, Octace, Matlab ... reproduzierbar. Der vorgeschlagene Betrug erklärt jedoch nicht, warum.

Ein Mann
quelle
10
Ich mag diese Antwort nicht - sie ist völlig handgewellt und erklärt die Ursache nicht wirklich. "Nun, tan (pi / 2) im Bogenmaß ist im Wesentlichen unendlich, nicht wahr?" erklärt nichts darüber, warum - wie das OP hier fragte - die Antwort nicht tatsächlich ist np.inf. Aber es ist einfach zu erklären, warum es nicht so ist, sondern auch zu erklären, warum die Antwort genau das ist, was gesehen wurde - und so habe ich es getan ;-)
Tim Peters

Antworten:

118

piist nicht genau als Python-Float darstellbar (wie der doubleTyp der Plattform C ). Die am nächsten darstellbare Näherung wird verwendet.

Hier ist die genaue Annäherung, die auf meiner Box verwendet wird (wahrscheinlich die gleiche wie auf Ihrer Box):

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

Um den Tangens dieses Verhältnisses zu finden, werde ich jetzt zu wxMaxima wechseln:

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

Also im Wesentlichen identisch mit dem, was du hast. Die verwendete binäre Näherung pi/2ist etwas kleiner als der mathematische Wert ("unendliche Genauigkeit") von pi/2. Sie erhalten also stattdessen eine sehr große Tangente infinity. Die berechnete tan()ist für die tatsächliche Eingabe geeignet!

Aus genau den gleichen Gründen, z.

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

gibt keine 0 zurück. Die Annäherung math.piist etwas kleiner als piund das angezeigte Ergebnis ist angesichts dieser Wahrheit korrekt .

ANDERE WEGE ZU SEHEN math.pi

Es gibt verschiedene Möglichkeiten, um die genaue verwendete Annäherung zu sehen:

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

math.pi ist genau gleich dem mathematischen Wert ("unendliche Genauigkeit") dieses Verhältnisses.

Oder als exakter Float in Hex-Notation:

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

Oder auf eine Weise, die für fast jeden am einfachsten zu verstehen ist:

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

Obwohl dies möglicherweise nicht sofort offensichtlich ist, ist jeder endliche binäre Float genau als endlicher Dezimal-Float darstellbar (das Gegenteil ist nicht der Fall; z. B. ist die Dezimalzahl 0.1nicht genau als endlicher binärer Float darstellbar), und der Decimal(some_float)Konstruktor erzeugt das genaue Äquivalent.

Hier ist der wahre Wert von pigefolgt vom exakten Dezimalwert von math.pi, und ein Caret in der dritten Zeile zeigt auf die erste Ziffer, wo sie sich unterscheiden:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.piist jetzt für "fast alle" Boxen gleich, da fast alle Boxen jetzt dasselbe binäre Gleitkommaformat verwenden (IEEE 754 doppelte Genauigkeit). Sie können eine der oben genannten Möglichkeiten verwenden, um dies auf Ihrer Box zu bestätigen oder um die genaue verwendete Annäherung zu ermitteln, wenn Ihre Box eine Ausnahme darstellt.

Tim Peters
quelle
@ Tim Peters - Das ist völlig klar. Der Vollständigkeit halber vermute ich, dass diese Darstellung von np.pider Epsilon des Systems am nächsten kommt?
Aguy
3
Angenommen, es np.pihat den gleichen Wert wie Python math.pi(ich habe es nicht überprüft, aber Sie können ;-)), ist es der Wert, der dem mathematischen pi am nächsten kommt, der im nativen C doubleGleitkommaformat der Plattform dargestellt werden kann. Dies bedeutet, dass IEEE 754 jetzt auf fast allen Boxen doppelte Genauigkeit aufweist und somit der nächste binäre Float mit 53 Bit (Mantissen-) Genauigkeit. Die Menge der Rationalen ist also auf die Form beschränkt, in der die +/- I * 2**JGanzzahl I0 oder 0 ist 2**52 <= I < 2**53, und der Bereich der Ganzzahl Jist weit genug, um alle Rationalen dieser Form irgendwo in der Nähe abzudecken pi.
Tim Peters
2
Und deshalb würde ich es lieben, wenn "binäre" trigonometrische Funktionen häufiger implementiert würden. Da pi niemals rational dargestellt werden kann, wäre es praktisch mit einer Reihe von Funktionen, die mit Winkeln von 0 bis 1 arbeiten.
Pipe
Nun, sie importierten np.pinicht math.pi.
EKons
2
@ Έρικ Κωνσταντόπουλος math.pi, np.piund scipy.pisind alle gleich; Sie werden nur zur Vereinfachung der Benennung dupliziert. stackoverflow.com/questions/12645547/…
Tim Peters