Existe um significado especial para 16331239353195370.0?

89

Usando import numpy as npeu notei que

np.tan(np.pi/2)

dá o número no título e não np.inf

16331239353195370.0

Estou curioso sobre este número. Está relacionado a algum parâmetro de precisão da máquina do sistema? Eu poderia ter calculado a partir de algo? (Estou pensando em algo semelhante a sys.float_info)

EDIT: O mesmo resultado é realmente reproduzível em outros ambientes como Java, octace, matlab ... O dupe sugerido não explica por que, no entanto.

Um cara
fonte
10
Não gosto dessa resposta - é inteiramente ondulada, não explica realmente a causa. "Bem, tan (pi / 2) em radianos é essencialmente infinito, não é?" não explica nada sobre por que - como o OP perguntou aqui - a resposta não é de fato np.inf. Mas é simples não apenas explicar por que não é, mas também explicar por que a resposta é exatamente o que foi visto - e foi o que fiz ;-)
Tim Peters

Respostas:

119

pinão é exatamente representável como Python float (igual ao tipo da plataforma C double). A aproximação representável mais próxima é usada.

Aqui está a aproximação exata em uso na minha caixa (provavelmente a mesma que na sua caixa):

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

Para encontrar a tangente dessa relação, vou mudar para wxMaxima agora:

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

Tão essencialmente idêntico ao que você conseguiu. A aproximação binária pi/2usada é um pouco menor do que o valor matemático ("precisão infinita") de pi/2. Então você obtém uma tangente muito grande em vez de infinity. O calculado tan()é apropriado para a entrada real!

Exatamente pelos mesmos motivos, por exemplo,

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

não retorna 0. A aproximação math.pié um pouco menor que pi, e o resultado exibido está correto dada essa verdade.

OUTRAS FORMAS DE VER math.pi

Existem várias maneiras de ver a aproximação exata em uso:

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

math.pi é exatamente igual ao valor matemático ("precisão infinita") dessa proporção.

Ou como um float exato em notação hexadecimal:

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

Ou da forma mais facilmente compreendida por quase todos:

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

Embora possa não ser imediatamente óbvio, todo float binário finito é exatamente representável como um float decimal finito (o inverso não é verdadeiro; por exemplo, o decimal 0.1não é exatamente representável como um float binário finito), e o Decimal(some_float)construtor produz o equivalente exato.

Aqui está o valor verdadeiro de piseguido pelo valor decimal exato de math.pi, e um circunflexo na terceira linha aponta para o primeiro dígito onde eles diferem:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.pié o mesmo em "quase todas" as caixas agora, porque quase todas as caixas agora usam o mesmo formato de ponto flutuante binário (precisão dupla IEEE 754). Você pode usar qualquer uma das maneiras acima para confirmar isso em sua caixa ou para encontrar a aproximação precisa em uso se sua caixa for uma exceção.

Tim Peters
fonte
@Tim Peters - Isso está perfeitamente claro. Para completar, estou supondo que esta representação de np.pié a representação racional mais próxima do épsilon do sistema?
Aguy
3
Supondo que np.pitenha o mesmo valor do Python math.pi(não verifiquei, mas você pode ;-)), é o valor mais próximo do pi matemático representável no C doubleformato de ponto flutuante nativo da plataforma . O que significa precisão dupla IEEE 754 em quase todas as caixas agora e, portanto, o flutuador binário mais próximo com 53 bits de precisão (mantissa). Portanto, o conjunto de racionais é restrito à forma em +/- I * 2**Jque inteiro Ié 0 ou 2**52 <= I < 2**53, e o intervalo de inteiro Jé amplo o suficiente para cobrir todos os racionais dessa forma em qualquer lugar próximo pi.
Tim Peters
2
E é por isso que eu adoraria se as funções trigonométricas "binárias" fossem mais comumente implementadas. Uma vez que pi nunca pode ser representado de forma racional, seria útil com um conjunto de funções operando em ângulos de 0 a 1.
tubo de
Bem, eles importaram np.pi, não math.pi.
EKons de
2
@ Έρικ Κωνσταντόπουλος math.pi, np.pie scipy.pisão todos iguais; eles são duplicados apenas por conveniência de nomenclatura; stackoverflow.com/questions/12645547/…
Tim Peters