C'è un significato speciale per 16331239353195370.0?


88

Usando l' import numpy as npho notato

np.tan(np.pi/2)

dà il numero nel titolo e non np.inf

16331239353195370.0

Sono curioso di questo numero. È correlato a qualche parametro di precisione della macchina del sistema? Potrei averlo calcolato da qualcosa? (Sto pensando sulla falsariga di qualcosa di simile a sys.float_info)

EDIT: Lo stesso risultato è effettivamente riproducibile in altri ambienti come Java, octace, matlab ... Il dupe suggerito non spiega perché, però.



10
Non mi piace quella risposta: è interamente ondulata, non spiega davvero la causa. "Beh, l'abbronzatura (pi / 2) in radianti è essenzialmente infinita, non è vero?" non spiega nulla sul perché - come l'OP ha chiesto qui - la risposta non è in realtà np.inf. Ma è semplice non solo spiegare perché non lo è, ma anche spiegare perché la risposta è esattamente ciò che è stato visto - e così ho fatto ;-)
Tim Peters

Risposte:


119

pinon è esattamente rappresentabile come float di Python (lo stesso del doubletipo C della piattaforma ). Viene utilizzata l'approssimazione rappresentabile più vicina.

Ecco l'approssimazione esatta in uso sulla mia scatola (probabilmente la stessa della tua scatola):

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

Per trovare la tangente di quel rapporto, ora passerò a wxMaxima:

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

Quindi essenzialmente identico a quello che hai ottenuto. L'approssimazione binaria da pi/2utilizzare è leggermente inferiore al valore matematico ("precisione infinita") di pi/2. Quindi ottieni una tangente molto grande invece di infinity. Il calcolo tan()è appropriato per l'input effettivo!

Per lo stesso tipo di motivi, ad es.

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

non restituisce 0. L'approssimazione math.piè leggermente inferiore a pi, e il risultato visualizzato è corretto data questa verità.

ALTRI MODI DI VEDERE math.pi

Esistono diversi modi per vedere l'approssimazione esatta in uso:

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

math.pi è esattamente uguale al valore matematico ("precisione infinita") di quel rapporto.

O come un float esatto in notazione esadecimale:

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

O in un modo più facilmente comprensibile da quasi tutti:

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

Anche se potrebbe non essere immediatamente ovvio, ogni float binario finito è esattamente rappresentabile come un float decimale finito (il contrario non è vero; ad esempio il decimale 0.1non è esattamente rappresentabile come un float binario finito) e il Decimal(some_float)costruttore produce l'equivalente esatto.

Ecco il vero valore di piseguito dal valore decimale esatto di math.pie un accento circonflesso sulla terza riga punta alla prima cifra in cui differiscono:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.piè lo stesso in "quasi tutte" le scatole ora, perché quasi tutte le scatole ora usano lo stesso formato binario a virgola mobile (IEEE 754 doppia precisione). Puoi utilizzare uno dei modi sopra per confermarlo sulla tua scatola, o per trovare l'approssimazione precisa in uso se la tua scatola è un'eccezione.


@Tim Peters - Questo è perfettamente chiaro. Per completezza, immagino che questa rappresentazione di np.pisia la rappresentazione razionale più vicina all'epsilon del sistema?
Aguy

3
Supponendo che np.piabbia lo stesso valore di Python math.pi(non ho controllato, ma puoi ;-)), è il valore più vicino al pi matematico rappresentabile nel C doubleformato a virgola mobile nativo della piattaforma . Il che significa IEEE 754 a doppia precisione su quasi tutte le scatole ora, e quindi il numero binario più vicino con 53 bit di precisione (mantissa). Quindi l'insieme dei razionali è vincolato alla forma in +/- I * 2**Jcui intero Iè 0 o 2**52 <= I < 2**53, e l'intervallo di interi Jè abbastanza ampio da coprire tutti i razionali di questa forma ovunque vicini pi.
Tim Peters

2
E questo è il motivo per cui mi piacerebbe amo se funzioni trigonometriche "binari" sono stati più comunemente implementati. Poiché il pi greco non può mai essere rappresentato in modo razionale, sarebbe utile con un insieme di funzioni che operano su angoli da 0 a 1.
pipe

Beh, hanno importato np.pi, no math.pi.
EKons

2
@ Έρικ Κωνσταντόπουλος math.pi, np.pie scipy.pisono tutti uguali; sono duplicati solo per comodità di denominazione; stackoverflow.com/questions/12645547/…
Tim Peters
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.