5

如果您将以下内容放入App Engine Shell中,您将获得'50.49'. 这个结果在 2.5 和 2.7 运行时都是一致的。

 >> a = '%0.2f' % (round(float(u'50.485'), 2),)
 >> a
'50.49'

但是,如果我将相同的东西放入运行 python 2.7.1 的本地 MacBook Pro 中,我会得到'50.48'.

 >> a = '%0.2f' % (round(float(u'50.485'), 2),)
 >> a
'50.48'

为什么会有所不同?如何才能在本地计算机和 App Engine 的服务器之间获得一致性?

4

3 回答 3

4

显然,Google App Engine 使用“float”C 类型(IEEE 754 单精度),而本地 Python 使用“double”代替(IEEE 754 双精度)。

我怀疑 CPython 有一个配置开关来使用“float”而不是“double”,但还没有找到。

于 2013-01-28T12:51:03.950 回答
2

有趣的是,官方 Python 教程中涵盖了这个确切的主题。

浮点运算:问题和限制
http://docs.python.org/2/tutorial/floatingpoint.html

其他惊喜随之而来。例如,如果您尝试将值 2.675 舍入到小数点后两位,您会得到这个

>>>
>>> round(2.675, 2)
2.67

内置 round() 函数的文档说它四舍五入到最接近的值,从零开始四舍五入。由于小数部分 2.675 恰好在 2.67 和 2.68 之间,您可能会期望这里的结果是(二进制近似)2.68。不是,因为当十进制字符串 2.675 转换为二进制浮点数时,它再次被二进制近似值替换,其精确值为

2.67499999999999982236431605997495353221893310546875

由于这个近似值比 2.68 更接近 2.67,因此向下舍入。

如果您关心的是小数中途情况的舍入方式,您应该考虑使用小数模块。顺便说一下,decimal 模块还提供了一种很好的方法来“查看”存储在任何特定 Python 浮点数中的确切值

>>>
>>> from decimal import Decimal
>>> Decimal(2.675)
Decimal('2.67499999999999982236431605997495353221893310546875')

尽管使用了 FORTRAN,但官方 Python 教程 ( http://www.lahey.com/float.htm ) 中链接的一篇文章正确地描述了 IEEE 754 的真正含义:

不同的计算机使用不同的位数来存储浮点数。即使使用相同的 IEEE 格式来存储数字,由于中间寄存器的大小,也会出现计算差异。为了增加可移植性并确保结果一致,我建议不要在 FORTRAN 中比较实数的精确相等性。

因此,如果您真的关心这一点,那么一定要使用内置的十进制模块(或 cdecimal 模块,如果性能是一个问题,请在此处获得http://pypi.python.org/pypi/cdecimal/2.3 )。

于 2013-01-28T12:41:15.843 回答
0

其他答案是正确的,所以我不会就round函数的行为说任何话,但是如果您想获得一致的结果,您可以跳过round,因为您使用的是'%0.2f'示例中显示的字符串格式 ( )。

>> a = '%0.2f' % (float(u'50.485'))
>> a
'50.48'
于 2013-01-28T13:08:11.157 回答