Почему sin (180) не равен нулю при использовании python и numpy?
Кто-нибудь знает, почему нижеследующее не равно 0?
import numpy as np
np.sin(np.radians(180))
или
np.sin(np.pi)
Когда я ввожу его в python, он дает мне 1.22e-16.
Ответы
Ответ 1
Число π
не может быть представлено точно как число с плавающей запятой. Итак, np.radians(180)
не дает вам π
, он дает вам 3.1415926535897931
.
И sin(3.1415926535897931)
на самом деле что-то вроде 1.22e-16
.
Итак, как вы справляетесь с этим?
Вы должны решить или, по крайней мере, угадать, соответствующие абсолютные и/или относительные границы ошибок, а затем вместо x == y
вы пишете:
abs(y - x) < abs_bounds and abs(y-x) < rel_bounds * y
(Это также означает, что вы должны упорядочить вычисления таким образом, чтобы относительная ошибка была больше относительно y
, чем x
. В вашем случае, поскольку y
является константой 0
, это тривиально- просто сделайте это назад.)
Numpy предоставляет функцию, которая делает это для вас по всему массиву, allclose
:
np.allclose(x, y, rel_bounds, abs_bounds)
(Это фактически проверяет abs(y - x) < abs_ bounds + rel_bounds * y)
, но это почти всегда достаточно, и вы можете легко реорганизовать свой код, когда он этого не делает.)
В вашем случае:
np.allclose(0, np.sin(np.radians(180)), rel_bounds, abs_bounds)
Итак, откуда вы знаете, каковы права? Нет никакого способа научить вас достаточному анализу ошибок в ответе SO. Распространение неопределенности в Википедии дает обзор на высоком уровне. Если вы действительно не знаете, вы можете использовать значения по умолчанию, которые 1e-5
relative и 1e-8
absolute.
Ответ 2
Одним из решений является переключение на sympy при вычислении sin и cos, а затем переключение обратно на numpy с помощью функции sp.N(...):
>>> # Numpy not exactly zero
>>> import numpy as np
>>> value = np.cos(np.pi/2)
6.123233995736766e-17
# Sympy workaround
>>> import sympy as sp
>>> def scos(x): return sp.N(sp.cos(x))
>>> def ssin(x): return sp.N(sp.sin(x))
>>> value = scos(sp.pi/2)
0
просто не забывайте использовать sp.pi вместо sp.np при использовании функций scos и ssin.
Ответ 3
Столкнулся с той же проблемой,
import numpy as np
print(np.cos(math.radians(90)))
>> 6.123233995736766e-17
и попробовал это,
print(np.around(np.cos(math.radians(90)), decimals=5))
>> 0
работал в моем случае. Я установил десятичную 5, чтобы не потерять слишком много информации. Как вы можете думать о функции округления избавиться после 5-значных значений.
Ответ 4
Попробуйте это... он обнуляет что-либо ниже заданного значения крошечного...
import numpy as np
def zero_tiny(x, threshold):
if (x.dtype == complex):
x_real = x.real
x_imag = x.imag
if (np.abs(x_real) < threshold): x_real = 0
if (np.abs(x_imag) < threshold): x_imag = 0
return x_real + 1j*x_imag
else:
return x if (np.abs(x) > threshold) else 0
value = np.cos(np.pi/2)
print(value)
value = zero_tiny(value, 10e-10)
print(value)
value = np.exp(-1j*np.pi/2)
print(value)
value = zero_tiny(value, 10e-10)
print(value)
Ответ 5
Проблема заключается не в ошибке округления pi.
Обратите внимание, что проблема не возникает для косинуса:
In [2]: np.sin(np.pi)
Out[2]: 1.2246467991473532e-16 != 0.
In [3]: np.cos(np.pi)
Out[3]: -1.0 == -1.
Проблема намного сложнее. Это связано с точностью pi внутри процессора. Это было обнаружено и объяснено здесь:
https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/