Используя import numpy as np
я заметил, что
np.tan(np.pi/2)
дает число в названии, а не np.inf
16331239353195370.0
Мне любопытно это число. Связано ли это с каким-то параметром системной машинной точности? Мог ли я рассчитать это из чего-нибудь? (Я думаю о чем-то похожем sys.float_info
)
РЕДАКТИРОВАТЬ: тот же результат действительно воспроизводится в других средах, таких как Java, octace, matlab ... Однако предлагаемый обман не объясняет, почему.
python
numpy
numerical-methods
Парень
источник
источник
np.inf
. Но просто не только объяснить, почему это не так, но и объяснить, почему ответ именно такой, как мы видели - и я так и сделал ;-)Ответы:
pi
не может быть точно представлен как Python с плавающей запятой (такой же, какdouble
тип платформы C ). Используется наиболее близкое представимое приближение.Вот точное приближение, используемое на моем ящике (вероятно, такое же, как и на вашем ящике):
>>> import math >>> (math.pi / 2).as_integer_ratio() (884279719003555, 562949953421312)
Чтобы найти тангенс этого отношения, я сейчас переключусь на wxMaxima:
(%i1) fpprec: 32; (%o1) 32 (%i2) tan(bfloat(884279719003555) / 562949953421312); (%o2) 1.6331239353195369755967737041529b16
По сути, идентично тому, что у вас есть. Используемое двоичное приближение
pi/2
немного меньше математического ("бесконечная точность") значенияpi/2
. Таким образом, вы получаете очень большую касательную вместоinfinity
. Вычисленноеtan()
подходит для фактического ввода!По точно таким же причинам, например,
>>> math.sin(math.pi) 1.2246467991473532e-16
не возвращает 0. Приближение
math.pi
немного меньшеpi
, и отображаемый результат верен, учитывая эту истину.ДРУГИЕ СПОСОБЫ ПОСМОТРЕНИЯ math.pi
Есть несколько способов увидеть, какое точное приближение используется:
>>> import math >>> math.pi.as_integer_ratio() (884279719003555, 281474976710656)
math.pi
в точности равно математическому («бесконечная точность») значению этого отношения.Или как точное число с плавающей запятой в шестнадцатеричной системе счисления:
>>> math.pi.hex() '0x1.921fb54442d18p+1'
Или способом, наиболее понятным практически каждому:
>>> import decimal >>> decimal.Decimal(math.pi) Decimal('3.141592653589793115997963468544185161590576171875')
Хотя это может быть не сразу очевидно, каждое конечное бинарное поплавок точно представима в виде конечной десятичной поплавка (обратное не верно, например , десятичную
0.1
не точно представимо в виде конечной двоичной поплавка), иDecimal(some_float)
конструктор производит точный эквивалент.Вот истинное значение, за
pi
которым следует точное десятичное значениеmath.pi
, а курсор в третьей строке указывает на первую цифру, где они различаются:true 3.14159265358979323846264338327950288419716939937510... math.pi 3.141592653589793115997963468544185161590576171875 ^
math.pi
то же самое для «почти всех» блоков теперь, потому что почти все блоки теперь используют один и тот же двоичный формат с плавающей запятой (двойная точность IEEE 754). Вы можете использовать любой из описанных выше способов, чтобы подтвердить это на вашем ящике, или найти точное приближение, которое используется, если ваш ящик является исключением.источник
np.pi
является наиболее близким рациональным представлением к эпсилону системы?np.pi
имеет то же значение, что и Pythonmath.pi
(я не проверял, но вы можете ;-)), это значение, наиболее близкое к математическому пи, представленному в собственномC double
формате с плавающей запятой платформы . Это означает двойную точность IEEE 754 теперь почти для всех ящиков и, следовательно, ближайший двоичный код с плавающей запятой с точностью 53 бита (мантисса). Таким образом, набор рациональных чисел ограничен формой, в+/- I * 2**J
которой целое числоI
равно 0 или2**52 <= I < 2**53
, а диапазон целых чиселJ
достаточно широк, чтобы охватить все рациональные числа этой формы где-либо поблизостиpi
.np.pi
, а не импортныеmath.pi
.math.pi
,np.pi
иscipy.pi
все одинаковы; они дублируются только для удобства именования; stackoverflow.com/questions/12645547/…