在round()函数中构建的Python在2.4和2.7之间的变化

时间:2011-12-20 22:22:52

标签: python floating-point python-2.7 floating-accuracy python-2.4

Python内置的round()函数是否在2.4和2.7之间变化?

Python 2.4:

Python 2.4.6 (#1, Feb 12 2009, 14:52:44)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f,2)
1480.4000000000001
>>>

Python 2.7:

Python 2.7.1 (r271:86832, May 13 2011, 08:14:41)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f, 2)
1480.39
>>>

无论如何都要恢复Python 2.4的行为?

我知道正确的答案当然是使用十进制算术模块。不幸的是,考虑到时间限制,这可能不是一个选择。

更新

对于上下文,我正在比较两个系统中的值,其中一个使用十进制表示,另一个使用浮点表示。这可能(或可能不是)需要进一步检查的系统之间的合法差异,因此我将咨询用户并在“报告”级别处理它,而不是在我从系统获取数据的时候

感谢您的帮助!

4 个答案:

答案 0 :(得分:6)

您的第一个问题的答案是:是的,round已在Python 2.7中修复。

你的第二个问题的答案是:我不确定,实际上没有使用早期的Python(2.6应该仍然表现出2.4的行为)。在这种特殊情况下,你的价值与1480.395和1480.395(对我们基数为10人)无法区分,为1480.40。所以我想你可以尝试首先四舍五入到一个超出你真正追求的地方,把它变成一个字符串,然后从那里得到一个十进制...但对不起,我想不出任何不涉及十进制的东西。如果我想到某些事情(在别人发布更好的事情之前),我会回来编辑。

(但实际上,十进制是难以使用的吗?)

编辑:以下是如何使用Decimal的示例:

>>> from decimal import Decimal
>>> f = Decimal('1480.395')
>>> f.quantize(Decimal('0.00'))
Decimal('1480.40')
>>> float(Decimal('1480.40'))
1480.4

一些注意事项:

Python 2.7允许您使用浮点数作为Decimal的输入。 不要这样做,就像你回到起点那样。另外,不要在Decimal上使用内置的round函数,因为该函数将把你的De​​cimal转换回float,因此你会回到你开始的地方。在最简单的形式中,Decimal的quantize采用另一个具有您真正想要的小数位数的Decimal(将其视为舍入的模板)。如果您的数据绝对必须是浮点数,那么只有在完成所有十进制计算后才转换回浮点数。

最后:我不确定这是否涵盖了Python 2.4浮动行为中所有可能的奇怪角落情况。如果您依赖完全 Python 2.4的行为,那么在Python 2.4上运行可能没有任何替代品。我上面所描述的仅仅是人类四舍五入的一步。

答案 1 :(得分:3)

可能不是因为Python 2.4实际上返回了错误的结果。由于您要将一个严格小于5的数量四舍五入,因此应该向下舍入正确的结果。

如果您能描述所需的确切行为,我们可能会创建另一种方法。

答案 2 :(得分:1)

what's new in python 2.6页面中,我看到以下内容(参考PEP 3141):

  

Python 3.0为受Scheme的数字塔启发的数字类型添加了几个抽象基类。这些类作为数字模块被反向移植到2.6。

...

  

在Python 3.0中,PEP稍微重新定义了现有的builtins round(),math.floor(),math.ceil(),并添加了一个新的math.trunc(),它已被反向移植到Python 2.6。 math.trunc()向零舍入,返回函数参数与零之间最接近的积分。

感谢@ mark-dickinson评论,在what's new in python 2.7页面中,找到了以下文字:

  

round()函数现在也正确舍入。

所以是的,改变发生在python 2.7中。这可以验证检查在python 2.6中行为仍然是旧行为:

Python 2.6.7 (r267:88850, Aug 11 2011, 12:18:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f, 2)
1480.4000000000001

在我的linux发行版中,我仍然可以访问python 2.6和python 2.7,也许你也可以访问你的;所以,如果你想要旧的行为,也许你可以尝试在python 2.6中运行代码。

答案 3 :(得分:0)

也许我在其他回复中遗漏了这一点,但实际上最后一个 Python 2.# 版本(版本 2.7.18)的 round 函数也不“正确”,即不符合 IEC 60559 标准.试试这个:

print(round(2.25, 1))

你应该得到 2.2不是 2.3。这在 3.# 版本中得到了修复(我只测试了 3.5 以后的版本)。