Есть ли у 16331239353195370.0 особое значение?

88

Используя import numpy as npя заметил, что

np.tan(np.pi/2)

дает число в названии, а не np.inf

16331239353195370.0

Мне любопытно это число. Связано ли это с каким-то параметром системной машинной точности? Мог ли я рассчитать это из чего-нибудь? (Я думаю о чем-то похожем sys.float_info)

РЕДАКТИРОВАТЬ: тот же результат действительно воспроизводится в других средах, таких как Java, octace, matlab ... Однако предлагаемый обман не объясняет, почему.

Парень
источник
11
stackoverflow.com/questions/12713790/…
Падрайк Каннингем
10
Мне не нравится этот ответ - он целиком и полностью невнятный, не совсем объясняющий причину. «Ну, tan (pi / 2) в радианах по сути бесконечен, не так ли?» как просили здесь OP - - ответ ничего о том, почему не объяснить это не на самом деле np.inf. Но просто не только объяснить, почему это не так, но и объяснить, почему ответ именно такой, как мы видели - и я так и сделал ;-)
Тим Питерс

Ответы:

119

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является наиболее близким рациональным представлением к эпсилону системы?
Aguy
3
Предполагая, что он np.piимеет то же значение, что и Python math.pi(я не проверял, но вы можете ;-)), это значение, наиболее близкое к математическому пи, представленному в собственном C doubleформате с плавающей запятой платформы . Это означает двойную точность IEEE 754 теперь почти для всех ящиков и, следовательно, ближайший двоичный код с плавающей запятой с точностью 53 бита (мантисса). Таким образом, набор рациональных чисел ограничен формой, в +/- I * 2**Jкоторой целое число Iравно 0 или 2**52 <= I < 2**53, а диапазон целых чисел Jдостаточно широк, чтобы охватить все рациональные числа этой формы где-либо поблизости pi.
Тим Питерс
2
И вот почему я люблю , если «бинарные» тригонометрические функции были более широко реализованы. Поскольку число пи никогда не может быть представлено в рациональном виде, было бы удобно использовать набор функций, работающих с углами от 0 до 1.
pipe
Ну они импортные np.pi, а не импортные math.pi.
EKons
2
@ Έρικ Κωνσταντόπουλος math.pi, np.piи scipy.piвсе одинаковы; они дублируются только для удобства именования; stackoverflow.com/questions/12645547/…
Тим Питерс