Задача с плавающей точкой по модулю - PullRequest
1 голос
/ 24 февраля 2010

Я наткнулся на очень странную ошибку. Прочитайте комментарии в коде, чтобы увидеть, в чем именно заключается ошибка, но по сути переменная по модулю 1 возвращает 1 (но она не равна 1!). Я предполагаю, что есть проблема с отображением, когда поплавок очень близок к единице, но не совсем. Тем не менее, он должен модулироваться до нуля. Я не могу проверить это легко, потому что (последний% 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

Ответы [ 5 ]

6 голосов
/ 24 февраля 2010

Печать не показывает полную точность числа в сохраненном виде, вы можете использовать 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
>>> 
6 голосов
/ 24 февраля 2010

Добро пожаловать в IEEE754, приятного пребывания .

3 голосов
/ 24 февраля 2010

Вы должны использовать 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, но результат Pye's -1e-100% 1e100 равен 1e100-1e-100, который не может быть представлен в точности как число с плавающей запятой, и округляет до удивительного 1e100 . По этой причине функция fmod () обычно предпочтительнее при работе с числами с плавающей запятой, в то время как x% y в Python предпочтительнее при работе с целыми числами. "

1 голос
/ 24 февраля 2010

Вы можете попробовать функцию math.fmod вместо last % 1, возможно, она лучше подходит для вашей проблемы. Или вы можете переформулировать свою проблему в целочисленном пространстве.

В любом случае, не рекомендуется сравнивать значения с плавающей запятой, используя оператор равенства ==, из-за неточных результатов даже при таких тривиальных операциях, как 0.1 + 0.2 == 0.3

0 голосов
/ 24 февраля 2010

Если вам нужна произвольная точность, есть несколько проектов, которые делают именно это. gmpy обрабатывает целые числа с высокой точностью, mpmath , который выглядит довольно хорошо, и bigfloat , который упаковывает MPFR. То, что у вас есть, может быть достаточно с помощью ответа Гнибблера, но на всякий случай.

...