Задача с плавающей запятой по модулю
-
22-09-2019 - |
Вопрос
Я наткнулся на очень странную ошибку.Прочитайте комментарии в коде, чтобы узнать, в чем именно заключается ошибка, но по сути переменная по модулю 1 возвращает 1 (но она не равна 1!).Я предполагаю, что существует проблема с отображением, когда значение float чрезвычайно близко к единице, но не точно.Однако он должен быть равен нулю по модулю.Я не могу легко протестировать этот случай, потому что (last % 1) != 1.0 !Когда я пытаюсь подключить те же числа к другому терминалу python, все работает правильно.Что происходит?
def r(k,i,p):
first = i*p
last = first + p
steps = int((i+1)*p) - int(i*p)
if steps < 1:
return p
elif steps >= 1:
if k == 0:
return 1 - (first % 1)
elif k == steps:
if i == 189:
print last, 1, type(last), last % 1, last - int(last)
# Prints: 73.0 1 <type 'float'> 1.0 1.0
print last % 1 == 1 # Returns False
if last % 1 == 1.0:
return 0
return (last % 1)
else:
return 1
Решение
Добро пожаловать в IEEE754, приятного вам пребывания.
Другие советы
Печать не показывает полную точность сохраненного числа, вы можете использовать repr()
чтобы сделать это
>>> last=72.99999999999999
>>> print last, 1, type(last), last % 1, last - int(last)
73.0 1 <type 'float'> 1.0 1.0
>>> print last % 1 == 1
False
>>> print repr(last), 1, type(last), repr(last%1), repr(last - int(last))
72.999999999999986 1 <type 'float'> 0.99999999999998579 0.99999999999998579
>>>
Вам следует использовать math.fmod(x, y).Вот выдержка из http://docs.python.org/library/math.html:
"Обратите внимание, что выражение Python x % y может не возвращать тот же результат.Цель стандарта C состоит в том, чтобы fmod(x, y) был точно (математически;с бесконечной точностью), равной x - n * y для некоторого целого числа n, такого, что результат имеет тот же знак, что и x, и величину, меньшую, чем abs (y).X % y в Python вместо этого возвращает результат со знаком y и может быть не совсем вычислимым для аргументов с плавающей точкой.Например, fmod(-1e-100, 1e100) равен -1e-100, но результатом Python -1e-100 % 1e100 является 1e100-1e-100, который не может быть представлен точно как значение с плавающей точкой, и раунды к удивительному 1e100.По этой причине функция fmod() обычно предпочтительнее при работе с числами с плавающей запятой, в то время как x % y в Python предпочтительнее при работе с целыми числами ".
Вы могли бы попробовать математика.fmod функция вместо last % 1
, может быть, это лучше подходит для вашей проблемы.Или вы могли бы переформулировать свою проблему в целочисленном пространстве.
В любом случае, не рекомендуется сравнивать значения с плавающей запятой, используя равенство ==
оператор, из-за неточных результатов даже от кажущихся тривиальными операций, таких как 0.1 + 0.2 == 0.3
Если вам нужна произвольная точность, есть несколько проектов, которые делают именно это. неуклюжий обрабатывает целые числа с высокой точностью, мпмат который выглядит довольно неплохо и большое плавание который обертывает MPFR.Того, что у вас есть, может быть достаточно из ответа gnibbler, но, на всякий случай.