Usando import numpy as np
he notado que
np.tan(np.pi/2)
da el número en el título y no np.inf
16331239353195370.0
Tengo curiosidad por este número. ¿Está relacionado con algún parámetro de precisión de la máquina del sistema? ¿Podría haberlo calculado a partir de algo? (Estoy pensando en algo similar a sys.float_info
)
EDITAR: El mismo resultado es de hecho reproducible en otros entornos como Java, octace, matlab ... Sin embargo, el engaño sugerido no explica por qué.
python
numpy
numerical-methods
Un chico
fuente
fuente
np.inf
. Pero es sencillo no solo explicar por qué no lo es, sino también explicar por qué la respuesta es exactamente lo que se vio, y así lo hice ;-)Respuestas:
pi
no es exactamente representable como Python float (igual que eldouble
tipo de la plataforma C ). Se utiliza la aproximación representable más cercana.Aquí está la aproximación exacta en uso en mi caja (probablemente la misma que en su caja):
>>> import math >>> (math.pi / 2).as_integer_ratio() (884279719003555, 562949953421312)
Para encontrar la tangente de esa relación, ahora voy a cambiar a wxMaxima:
(%i1) fpprec: 32; (%o1) 32 (%i2) tan(bfloat(884279719003555) / 562949953421312); (%o2) 1.6331239353195369755967737041529b16
Esencialmente idéntico a lo que tienes. La aproximación binaria a
pi/2
usada es un poco menor que el valor matemático ("precisión infinita") depi/2
. Entonces obtienes una tangente muy grande en lugar deinfinity
. ¡El calculadotan()
es apropiado para la entrada real!Exactamente por el mismo tipo de razones, por ejemplo,
>>> math.sin(math.pi) 1.2246467991473532e-16
no devuelve 0. La aproximación
math.pi
es un poco menor quepi
, y el resultado mostrado es correcto dada esa verdad.OTRAS FORMAS DE VER math.pi
Hay varias formas de ver la aproximación exacta en uso:
>>> import math >>> math.pi.as_integer_ratio() (884279719003555, 281474976710656)
math.pi
es exactamente igual al valor matemático ("precisión infinita") de esa relación.O como un flotador exacto en notación hexadecimal:
>>> math.pi.hex() '0x1.921fb54442d18p+1'
O de la manera más fácil de entender para casi todos:
>>> import decimal >>> decimal.Decimal(math.pi) Decimal('3.141592653589793115997963468544185161590576171875')
Si bien puede no ser inmediatamente obvio, cada flotante binario finito es exactamente representable como un flotante decimal finito (lo contrario no es cierto; por ejemplo, el decimal
0.1
no es exactamente representable como un flotante binario finito), y elDecimal(some_float)
constructor produce el equivalente exacto.Aquí está el valor real de
pi
seguido del valor decimal exacto demath.pi
, y un signo de intercalación en la tercera línea apunta al primer dígito donde difieren:true 3.14159265358979323846264338327950288419716939937510... math.pi 3.141592653589793115997963468544185161590576171875 ^
math.pi
es el mismo en "casi todos" los cuadros ahora, porque casi todos los cuadros ahora usan el mismo formato de punto flotante binario (IEEE 754 doble precisión). Puede utilizar cualquiera de las formas anteriores para confirmar eso en su caja, o para encontrar la aproximación precisa en uso si su caja es una excepción.fuente
np.pi
es la representación racional más cercana a la épsilon del sistema?np.pi
tiene el mismo valor que Pythonmath.pi
(no lo comprobé, pero puedes ;-)), es el valor más cercano al pi matemático representable en elC double
formato de punto flotante nativo de la plataforma . Lo que significa IEEE 754 de doble precisión en casi todas las cajas ahora, y por lo tanto, el flotador binario más cercano con 53 bits de precisión (mantisa). Por lo tanto, el conjunto de racionales está restringido a la forma+/- I * 2**J
donde el enteroI
es 0 o2**52 <= I < 2**53
, y el rango de números enterosJ
es lo suficientemente amplio como para cubrir todos los racionales de esta forma en cualquier lugar cercanopi
.np.pi
, nomath.pi
.math.pi
,np.pi
yscipy.pi
son todos iguales; están duplicados solo para facilitar el nombre; stackoverflow.com/questions/12645547/…