Python中的round()似乎没有正确舍入

时间:2008-09-11 15:08:09

标签: python floating-point rounding

round()函数的文档说明您将数字传递给它,并将小数点后的位置传递给舍入。因此应该这样做:

n = 5.59
round(n, 1) # 5.6

但是,实际上,良好的旧浮点怪异在悄悄进入,你得到:

5.5999999999999996

出于UI的目的,我需要显示5.6。我在互联网上搜索并找到了一些documentation,这取决于我对Python的实现。不幸的是,这发生在我的Windows开发机器和我尝试过的每台Linux服务器上。 See here also

没有创建我自己的圆形库,有什么方法可以解决这个问题吗?

20 个答案:

答案 0 :(得分:98)

我无法帮助它存储的方式,但至少格式化工作正常:

'%.1f' % round(n, 1) # Gives you '5.6'

答案 1 :(得分:98)

格式化工作正常,即使不必舍入:

"%.1f" % n

答案 2 :(得分:26)

如果使用Decimal模块,则可以在不使用“round”功能的情况下进行近似。以下是我用于舍入的内容,尤其是在编写货币申请时:

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

这将返回十进制数16.20。

答案 3 :(得分:20)

round(5.59, 1)工作正常。问题是5.6不能用二进制浮点精确表示。

>>> 5.6
5.5999999999999996
>>> 

正如Vinko所说,您可以使用字符串格式进行舍入以进行显示。

如果您需要,Python会有module for decimal arithmetic

答案 4 :(得分:12)

如果您执行str(round(n, 1))而非round(n, 1),则会获得“5.6”。

答案 5 :(得分:7)

您可以将数据类型切换为整数:

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

然后通过插入区域设置的小数分隔符来显示数字。

然而,Jimmy's answer更好。

答案 6 :(得分:5)

浮点数学很容易受到轻微但令人讨厌的精确误差的影响。如果你可以使用整数或固定点,你将保证精度。

答案 7 :(得分:5)

查看Decimal module

  

十进制“基于浮点数   与人共同设计的模型   记住,必然有一个   最重要的指导原则 -   计算机必须提供算术   它的工作方式与。相同   人们学习的算术   学校。“ - 小数摘录   算术规范。

  

可以表示十进制数字   究竟。相比之下,数字如1.1   和2.2没有确切的   二进制浮动表示   点。最终用户通常不会   期望1.1 + 2.2显示为   3.3000000000000003与二进制浮点一样。

Decimal提供了一种操作,可以轻松编写需要浮点运算的应用程序,需要以人类可读的格式显示这些结果,例如会计。

答案 8 :(得分:4)

这确实是一个大问题。试试这段代码:

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

显示4.85。然后你做:

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

,显示4.8。你手动计算确切答案是4.85,但如果你尝试:

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

你可以看到真相:浮点数被存储为最接近的分数的有限和,其分母是2的幂。

答案 9 :(得分:3)

printf 傻逼。

print '%.1f' % 5.59  # returns 5.6

答案 10 :(得分:3)

您可以使用字符串格式运算符%,类似于sprintf。

mystring = "%.2f" % 5.5999

答案 11 :(得分:3)

在这种情况下,我将完全避免依赖round()。考虑

print(round(61.295, 2))
print(round(1.295, 2))

将输出

61.3
1.29

,如果您需要将四舍五入到最接近的整数,则这不是期望的输出。要绕过此行为,请使用math.ceil()(如果要舍入,也可以使用math.floor()):

from math import ceil
decimal_count = 2
print(ceil(61.295 * 10 ** decimal_count) / 10 ** decimal_count)
print(ceil(1.295 * 10 ** decimal_count) / 10 ** decimal_count)

输出

61.3
1.3

希望有帮助。

答案 12 :(得分:2)

完美作品

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

答案 13 :(得分:2)

我在做:

int(round( x , 0))

在这种情况下,我们首先在单位级别正确舍入,然后转换为整数以避免打印浮点数。

所以

>>> int(round(5.59,0))
6

我认为这个答案比编写字符串更好,而且使用圆函数对我来说也更有意义。

答案 14 :(得分:1)

代码:

x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

输出:

5.6
5.7

答案 15 :(得分:0)

在这里,我看到圆形失败。如果您想将这两个数字舍入到一个小数位,该怎么办? 23.45 23.55 我的教育是通过四舍五入你应该得到: 23.4 23.6 "规则"如果前面的数字是奇数,你应该向上舍入,如果前面的数字是偶数,你不应该向上舍入。 python中的round函数只是截断5。

答案 16 :(得分:0)

问题仅在最后一位数为5时。 0.045在内部存储为0.044999999999999 ...您可以简单地将最后一位数字递增到6并舍入。这将为您提供所需的结果。

import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

答案 17 :(得分:0)

另一个可能的选择是:

def hard_round(number, decimal_places=0):
    """
    Function:
    - Rounds a float value to a specified number of decimal places
    - Fixes issues with floating point binary approximation rounding in python
    Requires:
    - `number`:
        - Type: int|float
        - What: The number to round
    Optional:
    - `decimal_places`:
        - Type: int 
        - What: The number of decimal places to round to
        - Default: 0
    Example:
    ```
    hard_round(5.6,1)
    ```
    """
    return int(number*(10**decimal_places)+0.5)/(10**decimal_places)

答案 18 :(得分:0)

这是一种将浮点数四舍五入到任意小数位的简单方法,它在 2021 年仍然有效!

float_number = 12.234325335563
rounded = round(float_number, 3) # 3 is the number of decimal places to be returned.You can pass any number in place of 3 depending on how many decimal places you want to return.
print(rounded)

这将打印;

12.234

答案 19 :(得分:-4)

怎么样:

round(n,1)+epsilon