首页 文章

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

提问于
浏览
101

round()函数的文档声明您将数字传递给它,并将小数点后的位置传递给圆形 . 因此它应该这样做:

n = 5.59
round(n, 1) # 5.6

但是,实际上,良好的旧浮点怪异爬进来,你会得到:

5.5999999999999996

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

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

17 回答

  • 3

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

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

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

    "%.1f" % n
    
  • 3

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

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

    这将返回十进制数16.20 .

  • 2

    round(5.59, 1) 工作正常 . 问题是5.6无法在二进制浮点中精确表示 .

    >>> 5.6
    5.5999999999999996
    >>>
    

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

    如果你需要,Python有一个module for decimal arithmetic .

  • 4

    如果你做 str(round(n, 1)) 而不是 round(n, 1) ,你会得到'5.6' .

  • 5

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

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

    然后通过插入语言环境的小数分隔符来显示数字 .

    但是,Jimmy's answer更好 .

  • 3

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

  • 19

    看看Decimal module

    Decimal“基于浮点模型,它是为人们设计的,并且必然具有最重要的指导原则 - 计算机必须提供与人们在学校学习的算法相同的算法 . ” - 摘录来自十进制算术规范 .

    十进制数字可以准确表示 . 相比之下,像1.1和2.2这样的数字在二进制浮点中没有精确的表示 . 最终用户通常不希望1.1 2.2显示为3.3000000000000003,因为它与二进制浮点一样 .

    Decimal提供了一种操作,使得编写需要浮点运算的应用程序变得容易,并且还需要以人类可读的格式(例如,会计)呈现这些结果 .

  • 94

    您可以使用字符串格式operator % ,类似于sprintf .

    mystring = "%.2f" % 5.5999
    
  • -1

    printf 傻逼 .

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

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

    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的幂 .

  • 12

    作品完美

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

    我在做:

    int(round( x , 0))
    

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

    所以

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

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

  • 7

    码:

    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
    
  • 1

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

  • -4

    问题是只有当最后一位数为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
    
  • 0

    关于什么:

    round(n,1)+epsilon
    

相关问题