Смягчение проблем аппроксимации чисел с плавающей точкой с Numpy - PullRequest
1 голос
/ 01 июля 2019

Мой код довольно прост, и только 1 строка вызывает проблему:

np.tan(np.radians(rotation))

Вместо ожидаемого результата для rotation = 45 как 1, я получаю 0.9999999999999999. Я понимаю, что 0 и тонна 9 равны 1. В моем случае, однако, это похоже на то, что определенно будет создаваться в течение итераций.

Что вызывает ошибку с плавающей запятой: np.tan или np.radians, и как я могу получить корректную работу функции задачи независимо от погрешностей с плавающей запятой?

Edit:

Я должен уточнить, что я знаком с неточностями с плавающей запятой. Меня беспокоит то, что по мере того, как это число умножается, добавляется и сравнивается, ошибка 1e-6 внезапно становится ощутимой. Обычно я мог безопасно игнорировать проблемы с плавающей запятой, но теперь я гораздо больше обеспокоен ростом ошибок. Я хотел бы уменьшить вероятность такой ошибки.

Редактировать 2:

Мое текущее решение - просто округлить до 8 десятичных знаков, потому что это, скорее всего, достаточно. Это своего рода временное решение, потому что я бы предпочел способ обойти десятичные представления IEEE.

Ответы [ 2 ]

1 голос
/ 02 июля 2019

Что вызывает ошибку с плавающей запятой: np.tan или np.radians, и как я могу получить корректную работу проблемной функции независимо от погрешностей с плавающей запятой?

Обе функции имеют ошибку округления, поскольку ни в одном случае точный результат не представляется в плавающей запятой.

Мое текущее решение - просто округлить до 8 десятичных знаков, потому что это, скорее всего, достаточно. Это своего рода временное решение, потому что я бы предпочел способ обойти десятичные представления IEEE.

Эта проблема не имеет ничего общего с десятичным представлением, и это даст худшие результаты за пределами того случая, который вы упомянули выше, например,

>>> np.tan(np.radians(60))
1.7320508075688767
>>> round(np.tan(np.radians(60)), 8)
1.73205081
>>> np.sqrt(3) # sqrt is correctly rounded, so this is the closest float to the true result
1.7320508075688772

Если вам абсолютно необходима более высокая точность, чем 15 десятичных цифр, которые вы получили бы из кода выше, тогда вы можете использовать произвольную библиотеку точности, такую ​​как gmpy2 .

0 голосов
/ 01 июля 2019

Посмотрите здесь: https://docs.scipy.org/doc/numpy/user/basics.types.html.

Стандартные dtypes в numpy не выходят за пределы точности 64 бит.Из документов:

Имейте в виду, что даже если np.longdouble предлагает большую точность, чем плавание Python, эту дополнительную точность легко потерять, так как питон часто заставляет значения проходить через float.Например, оператор форматирования % требует, чтобы его аргументы были преобразованы в стандартные типы Python, и поэтому невозможно сохранить расширенную точность, даже если запрашивается много десятичных разрядов.Может быть полезно проверить ваш код со значением 1 + np.finfo(np.longdouble).eps.

. Вы можете повысить точность с np.longdouble, но это зависит от платформы

В spyder (windows):

np.finfo(np.longdouble).eps  #same precision as float
>> 2.220446049250313e-16
np.finfo(np.longdouble).precision
>> 15

В Google Colab:

np.finfo(np.longdouble).eps  #larger precision
>> 1.084202172485504434e-19
np.finfo(np.longdouble).precision
>> 18

print(np.tan(np.radians(45, dtype=np.float), dtype=np.float) - 1)
print(np.tan(np.radians(45, dtype=np.longfloat), dtype=np.longfloat) - 1)
>> -1.1102230246251565e-16
0.0
...