Проблема модуля с плавающей точкой - PullRequest
3 голосов
/ 14 мая 2011

У меня проблема с модулем для числа с плавающей точкой в ​​Python.Этот код:

...
print '(' + repr(olddir) + ' + ' + repr(self.colsize) + ') % (math.pi*2) = ' + repr((olddir+self.colsize)
...

Печать:

(6.281876310240881 + 0.001308996938995747) % (math.pi*2) = 2.9043434324194095e-13

Я знаю, что числа с плавающей запятой не точны.Но я не могу понять, что это имеет смысл.

Я не знаю, связано ли это каким-либо образом, но Google Calculator также не может обработать этот расчет.Это вывод из Google Calculator:

(6.28187631024 + 0.001308996939) % (pi * 2) = 6.28318531

Что вызывает эту ошибку вычисления?И как я могу избежать этого в моей программе Python?

Ответы [ 2 ]

4 голосов
/ 14 мая 2011

Использование str() для печати числа с плавающей точкой фактически печатает округленную версию числа:

>>> print repr(math.pi)
3.1415926535897931
>>> print str(math.pi)
3.14159265359

Так что мы не можем воспроизвести ваши результаты, так как мы не знаем точных значенийВы делаете вычисления с.Очевидно, что точное значение olddir+self.colsize немного больше, чем 2*math.pi, тогда как сумма округленных значений, которые вы использовали в Google Calculator, немного меньше, чем 2*math.pi.

2 голосов
/ 14 мая 2011

Разница между str и repr

>>> import scipy
>>> pi = scipy.pi
>>> str(pi)
'3.14159265359'
>>> repr(pi)
'3.1415926535897931'

str усекает числа с плавающей запятой до 12 цифр, где repr дает внутреннее представление (в виде строки).

РЕДАКТИРОВАТЬ: Итак, в общем, проблема возникла потому, что вы преждевременно округлили и вычислили модуль чего-либо через число, которое очень близко к нему. Для чисел с плавающей точкой округление неизбежно связано с преобразованием десятичных чисел в двоичные.

Во-первых, приведите пример того, как округление вредит вам реальной математикой (не математикой с плавающей запятой). Посмотрите на (3.14 + 3.14)% (3.14 + 3.14), который, очевидно, равен нулю. Что произойдет, если мы округлим цифры до одной десятичной цифры сначала с одной стороны? Хорошо (3,1 + 3,1)% (3,14 + 3,14) = 6,2% (6,28) = 6,2 (что дал вам Google). Или если вы сделали раунд (3.14159,5) + раунд (3.14159,5)% (3.14159 + 3.14159) = 6,2832% 6,28318 = 2e-5.

Таким образом, округляя до N цифр (используя str, который эффективно округляет числа), ваш расчет будет точным только до N цифр. Для продолжения этой работы необходимо округление до некоторой старшей цифры (сохраняя две рассчитанные цифры для безопасности). Например, str округляет цифру 12, поэтому, возможно, нам следует округлить цифру 10.

>>> round(6.28187631024 + 0.001308996939,10) % (round(pi * 2,10))
0
...