2010-08-22 74 views
3

我是一个相当绿色的程序员,现在我正在学习Python。我到第17章中的“学会思考就像一个计算机科学家”(类和方法),我只是写了失败的方式我真的不完全我的第一个文档测试理解:Python中数值的陷阱,“有多深?”

class Point(object): 
    ''' 
    represents a point object. 
    attributes: x, y 
    ''' 

    def ___init___(self, x = 0, y = 0): 
     ''' 
     >>> point = Point() 
     >>> point.y 
     0 
     >>> point = Point(4.7, 8.2) 
     >>> point.x 
     4.7 
     ''' 

     self.x = x 
     self.y = y 

的第二个doctest为__init__失败,并返回4.7000000000000002而不是4.7。但是,如果我用“打印”语句重写doctest,如下所示:

>>> point = Point(4.7, 8.2) 
>>> print point.x 
4.7 

它运行正常。

所以我读到了Python如何存储浮动数据,现在我明白了,由于二进制表示的十进制数字,造成这种差异的原因是Python将4.7存储为1和0的字符串, t相当于4.7。

但我不明白的是为什么对“point.x”的调用返回4.7000000000000002,而对“print point.x”的调用返回4.7。在其他什么情况下,Python会选择像“打印”一样轮流?这个四舍五入工作如何?这些尾随的重要人物是否会导致编程错误(除了显然是失败的文档之外)?一个不注意四舍五入的人会产生危险的歧义吗?由于这与十进制数的二进制表示有关,我确定这实际上是一个通用的CS问题,而不是Python特有的问题,但我现在真正需要知道的是我可以做的,特别是作为Python程序员,以避免任何相关问题和/或错误感染。

另外,对于奖励积分,还有其他一些Python可以存储浮点数的方式,除了像“a = 4.7”这样的行激活的默认值吗?我知道有Decimal包,但我不完全确定它是如何工作的。老实说,所有这些动态打字的东西有时让我感到困惑。

编辑: 我应该指定,我使用的Python 2.6(在某些时候我想用与NumPy和Biopython)

+0

只要写4.5:对 – kennytm 2010-08-22 16:19:45

+4

最近的Python版本(2.7和3.1)即使没有“print”也会显示4.7。基本的不准确(由于浮点不精确)仍然存在。 – interjay 2010-08-22 16:22:53

回答

1

你得到不同的行为,因为print截断数字:

In [1]: 1.23456789
Out[1]: 1.23456789
In [2]: print 1.23456789
1.23456789012 

注意,在精度Python的彩车使用:

In [3]: 4.7 == 4.7000000000000002 
Out[3]: True 

钍是因为浮点数have a limited (relative) precision,因为它们使用有限数量的(二进制)数字来表示实数。因此,如上所述,给定数字的不同十进制表示对于Python来说实际上可能是相等的,然后用最接近的浮点数来近似。这是浮点数的一般属性。

2

当浮点数工作,常见的做法是这样的:

a == b if abs(a-b) <= eps, where eps is the required precision.

在程序设计竞赛,EPS与解决问题一起被给予的。 我的建议是建立一个你需要的东西的准确性,并使用它

3

这与计算机如何存储浮点数有关。这个的详细描述是here。但是,对于您的情况,快速解决方案是不检查point.x的打印表示,但是如果point.x等于4.7。所以......

>>> point = Point(4.7, 8.2) 
>>> point.x == 4.7 
True 

或者更好:

>>> point = Point(4.7, 8.2) 
>>> eps = 2**-53 #get epsilon for standard double precision number 
>>> -eps <= point.x - 4.7 <= eps 
True 

哪里eps是在浮点运算的舍入误差最大值。有关epsilon的详细信息,请参见here

编辑:-eps <= point.x - 4.7 <= eps相当于abs(point.x - 4.7) <= eps。我只是补充一点,因为不是每个人都熟悉Python的比较运算符链接。

编辑2:既然你提到numpy,numpy有一个方法来获得eps,而无需自己计算它。如果您使用的是numpy,请使用eps = numpy.finfo(float).eps而不是2**-53。请注意,numpy epsilon出于某种原因比应该大,等于2**-52而不是2**-53。我不知道这是为什么。

+2

机器epsilon是**相对**错误的界限。你不能像你那样使用它,因为对于远离零的值,绝对误差会更大。在这种特殊情况下,'point.x - 4.7'总是会给出0。 – interjay 2010-08-22 17:29:00

4
>>> point.x 

电话repr功能这是字符串表示持有更多的技术信息超过str函数,该函数调用时

>>> print point.x 

发生

+1

谢谢你回答我应该问的问题 – tel 2010-08-22 18:03:01