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

Использование import numpy as np Я заметил, что

np.tan(np.pi/2)

дает номер в заголовке, а не np.inf

16331239353195370.0

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

EDIT: Тот же результат действительно воспроизводится в других средах, таких как Java, octace, matlab... Предлагаемый обман не объясняет, почему.

Ответ 1

pi не является точно представимым как плавающий Python (такой же, как тип платформы C double). Используется наиболее близкое представимое приближение.

Здесь точная аппроксимация в моем ящике (вероятно, такая же, как на вашем ящике):

>>> 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')

В то время как это может быть не сразу очевидным, каждый конечный двоичный float точно представлен как конечный десятичный float (обратное неверно, например, десятичное 0.1 не является точно представимым как конечный двоичный float), а Decimal(some_float) создает точный эквивалент.

Здесь истинное значение pi, за которым следует точное десятичное значение math.pi, а каретка на третьей строке указывает на первую цифру, в которой они отличаются:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.pi теперь одно и то же для "почти всех", потому что почти все ящики теперь используют один и тот же двоичный формат с плавающей запятой (двойная точность IEEE 754). Вы можете использовать любой из приведенных выше способов, чтобы подтвердить, что на вашем поле, или найти точное приближение в использовании, если ваш ящик является исключением.