代码之家  ›  专栏  ›  技术社区  ›  Mercury

圆函数的行为不一致[重复]

  •  1
  • Mercury  · 技术社区  · 6 年前

    我只是在重读 What’s New In Python 3.0 它说:

    round()函数的舍入策略和返回类型已更改。 现在,精确的中间情况取而代之的是四舍五入到最接近的偶数结果 从零开始。(例如,round(2.5)现在返回2,而不是1。) 3.)

    和 文件 round :

    对于支持round()的内置类型,值被舍入到 幂减n的最接近10的倍数;如果两个倍数是 同样接近,四舍五入是朝着均匀的选择进行的

    所以,在 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推出时,一定有人讨论过 但我在寻找的过程中找不到一个好的理由。

    1. 有人知道为什么会变成这样吗?
    2. 是否有其他主流编程语言(例如。, C,C++,java,perl, ..)这样做(对我来说不一致)舍入?

    我错过了什么?

    更新:@Li aungYip关于“银行取整”的评论给了我正确的搜索词/关键词,我发现了这个问题: Why does .NET use banker's rounding as default? ,所以我会仔细阅读。

    0 回复  |  直到 9 年前
        1
  •  194
  •   Boris Verkhovskiy Brian Clapper    6 年前

    Python 3的方式(被称为“ round half to even “或“银行家舍入法”)被认为是当今的标准舍入方法,尽管有些语言实现还没有出现在总线上。

    “简单” always round 0.5 up “这种技术会导致略微偏向更高的数字。通过大量的计算,这可能是非常重要的。Python 3.0方法消除了这个问题。

    常用的四舍五入方法不止一种。国际浮点数学标准IEEE 754定义了 five different rounding methods (Python 3.0使用的是默认设置)。和 there are others .

    这种行为并不像应有的那样广为人知。如果我没记错的话,AppleScript是这种舍入方法的早期采用者。这个 round command in AppleScript 提供了几个选项,但在IEEE 754中,舍入到偶数是默认值。显然是实施这项计划的工程师 圆形的 司令部受够了所有“让它像我在学校学到的那样工作”的要求,于是他实施了: round 2.5 rounding as taught in school 是有效的AppleScript命令。:-)

        2
  •  46
  •   Barthelemy    12 年前

    您可以使用 Decimal module :

    >>> 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')
    
        3
  •  20
  •   skif1979    12 年前

    只需在此处添加文档中的一个重要注释:

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

    笔记

    float的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)
    
        4
  •  10
  •   kares    7 年前

    Python 3。x将0.5个值舍入一个偶数的邻居

    assert round(0.5) == 0
    assert round(1.5) == 2
    assert round(2.5) == 2
    
    import decimal
    
    assert decimal.Decimal('0.5').to_integral_value() == 0
    assert decimal.Decimal('1.5').to_integral_value() == 2
    assert decimal.Decimal('2.5').to_integral_value() == 2
    

    但是,如果需要,可以将十进制四舍五入“后退”改为始终四舍五入

    decimal.getcontext().rounding = decimal.ROUND_HALF_UP
    
    assert decimal.Decimal('0.5').to_integral_value() == 1
    assert decimal.Decimal('1.5').to_integral_value() == 2
    assert decimal.Decimal('2.5').to_integral_value() == 3
    
    i = int(decimal.Decimal('2.5').to_integral_value()) # to get an int
    assert i == 3
    assert type(i) is int
    
        5
  •  8
  •   narnie    13 年前

    我最近也遇到了一些问题。因此,我开发了一个python 3模块,它有两个函数trueround()和trueround_precision(),它们解决了这个问题,并给出了小学时使用的相同舍入行为(不是银行家舍入)。这是模块。只需保存代码并将其复制或导入即可。注:trueround_precision模块可以根据需要根据十进制模块中的ROUND_天花板、ROUND_DOWN、ROUND_地板、ROUND_HALF_DOWN、ROUND_HALF_偶数、ROUND_HALF_UP、ROUND_UP和ROUND_05UP标志更改舍入行为(有关更多信息,请参阅该模块文档)。对于下面的函数,请参阅docstrings或使用帮助(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)
    

    希望这有帮助,

    纳尼

        6
  •  4
  •   Smart Manoj AlexP    8 年前

    Python 3中的Python 2舍入行为。

    在小数点后15位加1。 精度高达15位。

    round2=lambda x,y=None: round(x+1e-15,y)
    
        7
  •  2
  •   Virako    7 年前

    有些情况:

    in: Decimal(75.29 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
    in: round(75.29 / 2, 2)
    out: 37.65 GOOD
    
    in: Decimal(85.55 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
    in: round(85.55 / 2, 2)
    out: 42.77 BAD
    

    修复方法:

    in: round(75.29 / 2 + 0.00001, 2)
    out: 37.65 GOOD
    in: round(85.55 / 2 + 0.00001, 2)
    out: 42.78 GOOD
    

    如果你想要更多的小数,例如4,你应该加(+0.0000001)。

    为我工作。

        8
  •  0
  •   Fallenreaper    7 年前

    样本复制:

    ['{} => {}'.format(x+0.5, round(x+0.5)) for x in range(10)]
    
    ['0.5 => 0', '1.5 => 2', '2.5 => 2', '3.5 => 4', '4.5 => 4', '5.5 => 6', '6.5 => 6', '7.5 => 8', '8.5 => 8', '9.5 => 10']
    

    应用程序编程接口: https://docs.python.org/3/library/functions.html#round

    各国:

    返回小数点后四舍五入到ndigits精度的数字。如果 ndigits被省略或为None,它将返回最接近其值的整数 输入

    对于支持round()的内置类型,值被舍入到 最接近幂减去ndigit的10倍;如果两个倍数 同样接近,四舍五入是朝着偶数选择进行的(例如 例如,圆形(0.5)和圆形(-0.5)都是0,圆形(1.5)是2)。 任何整数值都对ndigit有效(正、零或负)。 如果省略ndigits或无ndigits,则返回值为整数。 否则,返回值的类型与number相同。

    对于一般Python对象编号,将代理四舍五入为 数字 圆形的 .

    注意,float的round()的行为可能令人惊讶:例如 例如,四舍五入(2.675,2)得到的是2.67,而不是预期的2.68。这 这不是一个错误:它是大多数小数的结果 不能精确地表示为浮点数。参见浮点 算术:更多信息的问题和限制。

    鉴于这一点,你可以用一些数学来解决它

    import math
    def my_round(i):
      f = math.floor(i)
      return f if i - f < 0.5 else f+1
    

    现在,您可以用my_round而不是round运行相同的测试。

    ['{} => {}'.format(x + 0.5, my_round(x+0.5)) for x in range(10)]
    ['0.5 => 1', '1.5 => 2', '2.5 => 3', '3.5 => 4', '4.5 => 5', '5.5 => 6', '6.5 => 7', '7.5 => 8', '8.5 => 9', '9.5 => 10']
    
        9
  •  -3
  •   sunwarr10r    6 年前

    在Python3中进行循环的最简单方法。学校教授的x使用辅助变量:

    n = 0.1 
    round(2.5 + n)
    

    这些将是系列2.0到3.0(0.1步)的结果:

    >>> round(2 + n)
    >>> 2
    
    >>> round(2.1 + n)
    >>> 2
    
    >>> round(2.2 + n)
    >>> 2
    
    >>> round(2.3 + n)
    >>> 2
    
    >>> round(2.4 + n)
    >>> 2
    
    >>> round(2.5 + n)
    >>> 3
    
    >>> round(2.6 + n)
    >>> 3
    
    >>> round(2.7 + n)
    >>> 3
    
    >>> round(2.8 + n)
    >>> 3
    
    >>> round(2.9 + n)
    >>> 3
    
    >>> round(3 + n)
    >>> 3
    
        10
  •  -4
  •   Ṃųỻịgǻňạcểơửṩ    6 年前

    请尝试以下代码:

    def roundup(input):   
       demo = input  if str(input)[-1] != "5" else str(input).replace("5","6")
       place = len(demo.split(".")[1])-1
       return(round(float(demo),place))
    

    结果将是:

    >>> x = roundup(2.5)
    >>> x
    3.0  
    >>> x = roundup(2.05)
    >>> x
    2.1 
    >>> x = roundup(2.005)
    >>> x
    2.01 
    

    输出您可以在这里查看: https://i.stack.imgur.com/QQUkS.png

        11
  •  -6
  •   Eds_k    6 年前

    你可以用数学来控制四舍五入。ceil模块:

    import math
    print(math.ceil(2.5))
    > 3