Używając import numpy as np
zauważyłem to
np.tan(np.pi/2)
podaje numer w tytule, a nie np.inf
16331239353195370.0
Ciekawi mnie ten numer. Czy jest to związane z jakimś parametrem precyzji maszyny systemowej? Czy mogłem to obliczyć z czegoś? (Myślę w stylu czegoś podobnego do sys.float_info
)
EDYCJA: Ten sam wynik jest rzeczywiście odtwarzalny w innych środowiskach, takich jak Java, octace, matlab ... Jednak sugerowany duplikat nie wyjaśnia dlaczego.
python
numpy
numerical-methods
Koleś
źródło
źródło
np.inf
. Ale to nie tylko prosta do wyjaśnienia, dlaczego tak nie jest, ale również wyjaśnić, dlaczego odpowiedź jest dokładnie to, co było postrzegane - i tak zrobiłem ;-)Odpowiedzi:
pi
nie jest dokładnie reprezentowalny jako zmiennoprzecinkowy Pythona (taki sam jakdouble
typ platformy C ). Stosowane jest najbliższe reprezentatywne przybliżenie.Oto dokładne przybliżenie używane na moim pudełku (prawdopodobnie takie samo jak na twoim pudełku):
>>> import math >>> (math.pi / 2).as_integer_ratio() (884279719003555, 562949953421312)
Aby znaleźć styczną tego współczynnika, przełączę się teraz na wxMaxima:
(%i1) fpprec: 32; (%o1) 32 (%i2) tan(bfloat(884279719003555) / 562949953421312); (%o2) 1.6331239353195369755967737041529b16
Więc zasadniczo identyczny z tym, co masz. Stosowane przybliżenie binarne
pi/2
jest nieco mniejsze niż wartość matematyczna („nieskończona precyzja”)pi/2
. Otrzymujesz więc bardzo dużą styczną zamiastinfinity
. Obliczonatan()
jest odpowiednia dla rzeczywistego wejścia!Z dokładnie tych samych powodów, np.
>>> math.sin(math.pi) 1.2246467991473532e-16
nie zwraca 0. Przybliżenie
math.pi
jest trochę mniejsze niżpi
, a wyświetlany wynik jest poprawny, biorąc pod uwagę tę prawdę.INNE SPOSOBY WIDZENIA math.pi
Istnieje kilka sposobów, aby zobaczyć dokładne przybliżenie w użyciu:
>>> import math >>> math.pi.as_integer_ratio() (884279719003555, 281474976710656)
math.pi
jest dokładnie równa matematycznej („nieskończonej precyzji”) wartości tego stosunku.Lub jako dokładny float w notacji szesnastkowej:
>>> math.pi.hex() '0x1.921fb54442d18p+1'
Lub w sposób najłatwiejszy do zrozumienia dla każdego:
>>> import decimal >>> decimal.Decimal(math.pi) Decimal('3.141592653589793115997963468544185161590576171875')
Chociaż może to nie być od razu oczywiste, każda skończona liczba binarna zmiennoprzecinkowa jest dokładnie reprezentowalna jako skończona liczba dziesiętna (odwrotność nie jest prawdą; np. Liczba dziesiętna
0.1
nie jest dokładnie reprezentowalna jako skończona liczba binarna zmiennoprzecinkowa), aDecimal(some_float)
konstruktor tworzy dokładny odpowiednik.Oto prawdziwa wartość,
pi
po której następuje dokładna wartość dziesiętnamath.pi
, a daszek w trzecim wierszu wskazuje na pierwszą cyfrę, w której się różnią:true 3.14159265358979323846264338327950288419716939937510... math.pi 3.141592653589793115997963468544185161590576171875 ^
math.pi
jest teraz taka sama dla „prawie wszystkich” pudełek, ponieważ prawie wszystkie skrzynki używają teraz tego samego binarnego formatu zmiennoprzecinkowego (podwójna precyzja IEEE 754). Możesz użyć dowolnego z powyższych sposobów, aby potwierdzić to na swoim pudełku lub znaleźć dokładne przybliżenie w użyciu, jeśli Twoje pudełko jest wyjątkiem.źródło
np.pi
jest najbliższą racjonalną reprezentacją w obrębie epsilonu systemu?np.pi
ma taką samą wartość jak Pythonmath.pi
(nie sprawdzałem, ale możesz ;-)), jest to wartość najbliższa matematycznemu pi reprezentowanemu w natywnymC double
formacie zmiennoprzecinkowym platformy . Co oznacza podwójną precyzję IEEE 754 na prawie wszystkich pudełkach teraz, a więc najbliższy binarny float z 53 bitami (mantysy) precyzji. Zatem zbiór wymiernych jest ograniczony do postaci, w+/- I * 2**J
której liczba całkowitaI
jest równa 0 lub2**52 <= I < 2**53
, a zakres liczb całkowitychJ
jest wystarczająco szeroki, aby objąć wszystkie wymierne tej postaci w dowolnym miejscu w pobliżupi
.np.pi
, niemath.pi
.math.pi
,np.pi
iscipy.pi
wszystkie są takie same; są duplikowane tylko dla wygody nazewnictwa; stackoverflow.com/questions/12645547/…