浮点数取模问题

3

我在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 计算器也无法处理此计算。以下是 Google 计算器的输出:

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

什么导致了这个计算错误?我该如何在Python程序中避免它?

现在你已经编辑了这些值,很难看出计算错误在哪里。你期望得到什么结果? - Mark Ransom
@Mark:看看原帖中对我的回答的评论,了解实际问题是什么。 - Sven Marnach
1
@Sven,谢谢 - 我已经知道科学计数法很长时间了,以至于它变得无形。我忘记了一开始看起来有多令人困惑。 - Mark Ransom
2个回答

4

使用str()函数打印浮点数时,实际上会打印该数的四舍五入版本:

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

因为我们不知道您计算时所使用的确切值,所以我们无法真正复现您的结果。显然,olddir+self.colsize 的确切值略大于 2*math.pi,而您在 Google 计算器中使用的四舍五入后的值之和略小于 2*math.pi


我已经更新了我的帖子,使用repr()代替str()。现在应该可以重现,尽管我不知道为什么这很重要。 - paldepind
1
@paldepind: 现在用新的值在Google中尝试一下(http://www.google.com/search?q=%286.281876310240881+%2B+0.001308996938995747%29+%25+%28pi%2a2%29),看看为什么它很重要。 - Sven Marnach
是的,现在它与谷歌计算器匹配了。但这个计算结果还是错误的。它应该返回接近零的值。 - paldepind
1
@paldepind:看一下维基百科对这种表示法的解释 - Sven Marnach
1
@paldepind,你不是傻 - 只是缺乏经验。这没有什么可羞耻的。 - Mark Ransom

2

The difference between str and 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(这是谷歌给你的)。或者如果您执行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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接