Python 3.x舍入行为

我刚刚重新阅读了Python 3.0中的新增function ,并指出:

round()函数舍入策略和返回types已更改。 准确的中途情况现在四舍五入到最接近的结果,而不是从零开始。 (例如,round(2.5)现在返回2而不是3)

和一轮的文件:

对于支持round()的内置types,将值四舍五入为功率减n的10的最接近倍数; 如果两个倍数相等,则舍入为偶数select

所以,在v2.7.3下:

In [85]: round(2.5) Out[85]: 3.0 In [86]: round(3.5) Out[86]: 4.0 

正如我所料。 但是,现在在v3.2.3下:

 In [32]: round(2.5) Out[32]: 2 In [33]: round(3.5) Out[33]: 4 

这看起来是违反直觉的,与我对四舍五入的理解是相反的(并且会绊倒人)。 英语不是我的母语,但直到我读到这个,我以为我知道四舍五入是什么意思: – /我相信在引入v3的时候,一定有一些这样的讨论,但我无法find一个很好的理由我的search。

  1. 有没有人有洞察到为什么这改变了?
  2. 有没有其他的主stream编程语言(例如, C,C ++,Java,Perl, ..)这样做(对我来说是不一致的)四舍五入?

我在这里错过了什么?

更新:@ Li-aungYip的评论“银行家的四舍五入”给了我正确的search词/关键字search,我发现这个问题: 为什么.NET使用银行家舍入为默认? ,所以我会仔细阅读。

目前Python 3.0的方式被认为是标准的四舍五入方法,尽pipe一些语言实现还没有在总线上。

简单的“始终围绕0.5上涨”的技术导致稍微偏向于更高的数字。 大量的计算,这可能是重要的。 Python 3.0方法消除了这个问题。

有不止一种四舍五入的方法。 IEEE 754是浮点math的国际标准,定义了五种不同的舍入方法 (Python 3.0使用的是默认方法)。 还有其他的。

这种行为并不像它应该那样广为人知。 如果我没有记错的话,AppleScript是这个四舍五入方法的早期采用者。 AppleScript中的round命令实际上提供了几个选项,但是在IEEE 754中默认是round-even-even。显然,执行round命令的工程师对所有请求感到厌倦,“让它像我一样工作在学校学习“,他实现了这一点: round 2.5 rounding as taught in school是一个有效的AppleScript命令。 🙂

您可以使用十进制模块控制您在Py3000中获得的舍入:

 >>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP) >>> Decimal('4') >>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_EVEN) >>> Decimal('2') >>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN) >>> Decimal('3') 

只是在这里添加一个来自文档的重要说明:

https://docs.python.org/dev/library/functions.html#round

注意

round()对于浮点数的行为可能会令人惊讶:例如round(2.675,2)给出2.67,而不是预期的2.68。 这不是一个错误:这是大多数小数不能完全表示为浮点数的结果。 有关更多信息,请参见浮点算术:问题和限制。

所以,在Python 3.2中获得以下结果不要感到惊讶:

 >>> round(0.25,1), round(0.35,1), round(0.45,1), round(0.55,1) (0.2, 0.3, 0.5, 0.6) >>> round(0.025,2), round(0.035,2), round(0.045,2), round(0.055,2) (0.03, 0.04, 0.04, 0.06) 

我最近也遇到了这个问题。 因此,我开发了一个具有两个函数trueround()和trueround_precision()的python 3模块来解决这个问题,并给出了从小学(不是银行家四舍五入)使用的相同舍入行为。 这是模块。 只需保存代码并将其复制或导入即可。 注意:trueround_precision模块可根据需要根据十进制模块中的ROUND_CEILING,ROUND_DOWN,ROUND_FLOOR,ROUND_HALF_DOWN,ROUND_HALF_EVEN,ROUND_HALF_UP,ROUND_UP和ROUND_05UP标志更改舍入行为(有关详细信息,请参阅模块文档)。 对于下面的函数,请参阅文档string或使用帮助(trueround)和帮助(trueround_precision)如果复制到解释器进一步文档。

 #! /usr/bin/env python3 # -*- coding: utf-8 -*- def trueround(number, places=0): ''' trueround(number, places) example: >>> trueround(2.55, 1) == 2.6 True uses standard functions with no import to give "normal" behavior to rounding so that trueround(2.5) == 3, trueround(3.5) == 4, trueround(4.5) == 5, etc. Use with caution, however. This still has the same problem with floating point math. The return object will be type int if places=0 or a float if places=>1. number is the floating point number needed rounding places is the number of decimal places to round to with '0' as the default which will actually return our interger. Otherwise, a floating point will be returned to the given decimal place. Note: Use trueround_precision() if true precision with floats is needed GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail.com> ''' place = 10**(places) rounded = (int(number*place + 0.5if number>=0 else -0.5))/place if rounded == int(rounded): rounded = int(rounded) return rounded def trueround_precision(number, places=0, rounding=None): ''' trueround_precision(number, places, rounding=ROUND_HALF_UP) Uses true precision for floating numbers using the 'decimal' module in python and assumes the module has already been imported before calling this function. The return object is of type Decimal. All rounding options are available from the decimal module including ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP. examples: >>> trueround(2.5, 0) == Decimal('3') True >>> trueround(2.5, 0, ROUND_DOWN) == Decimal('2') True number is a floating point number or a string type containing a number on on which to be acted. places is the number of decimal places to round to with '0' as the default. Note: if type float is passed as the first argument to the function, it will first be converted to a str type for correct rounding. GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail.com> ''' from decimal import Decimal as dec from decimal import ROUND_HALF_UP from decimal import ROUND_CEILING from decimal import ROUND_DOWN from decimal import ROUND_FLOOR from decimal import ROUND_HALF_DOWN from decimal import ROUND_HALF_EVEN from decimal import ROUND_UP from decimal import ROUND_05UP if type(number) == type(float()): number = str(number) if rounding == None: rounding = ROUND_HALF_UP place = '1.' for i in range(places): place = ''.join([place, '0']) return dec(number).quantize(dec(place), rounding=rounding) 

希望这可以帮助,

Narnie

在Python 3 Python 2舍入行为

在小数点后20位加1,round2 = lambda x,y:round(x + 1e-20,y)