浮点数取模问题
我在Python中遇到了关于浮点数取模的问题。这个代码:
...
print '(' + repr(olddir) + ' + ' + repr(self.colsize) + ') % (math.pi*2) = ' + repr((olddir+self.colsize)
...
输出是:
(6.281876310240881 + 0.001308996938995747) % (math.pi*2) = 2.9043434324194095e-13
我知道浮点数不太精确。但我就是搞不懂这是怎么回事。
我不知道这是否有关系,但谷歌计算器也无法处理这个计算。谷歌计算器的输出是:
(6.28187631024 + 0.001308996939) % (pi * 2) = 6.28318531
是什么导致了这个计算错误?我该如何在我的Python程序中避免这个问题?
2 个回答
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(这是谷歌给你的结果)。或者如果你先对3.14159进行round(3.14159,5)然后再加上round(3.14159,5),再对(3.14159 + 3.14159)进行模运算,结果是6.2832 % 6.28318 = 2e-5。
所以,通过使用str
进行N位数字的四舍五入,你的计算结果的准确性只会低于N位数字。为了让这个计算在未来有效,强制在更高的位数进行四舍五入(保留两位计算结果以确保安全)是必要的。例如,str
在第12位进行四舍五入,所以也许我们应该在第10位进行四舍五入。
>>> round(6.28187631024 + 0.001308996939,10) % (round(pi * 2,10))
0
使用 str()
来打印一个浮点数时,实际上打印的是这个数字的一个近似值:
>>> print repr(math.pi)
3.1415926535897931
>>> print str(math.pi)
3.14159265359
所以我们无法完全复现你的结果,因为我们不知道你计算时使用的确切数值。显然,olddir+self.colsize
的确切值稍微大于 2*math.pi
,而你在谷歌计算器中使用的近似值的总和则稍微小于 2*math.pi
。