round() 似乎没有正确舍入

2025-02-17 09:25:00
admin
原创
52
摘要:问题描述:round()函数的文档指出,您向其传递一个数字,并将小数点后的位置四舍五入。因此它应该这样做:n = 5.59 round(n, 1) # 5.6 但实际上,古老的浮点怪异现象悄然出现,你会得到:5.5999999999999996 为了实现 UI,我需要显示5.6。我在网上搜索了一下,发现一些文...

问题描述:

round()函数的文档指出,您向其传递一个数字,并将小数点后的位置四舍五入。因此它应该这样做:

n = 5.59
round(n, 1) # 5.6

但实际上,古老的浮点怪异现象悄然出现,你会得到:

5.5999999999999996

为了实现 UI,我需要显示5.6。我在网上搜索了一下,发现一些文档表明这取决于我的 Python 实现。不幸的是,这种情况发生在我的 Windows 开发机器和我尝试过的每个 Linux 服务器上。另请参阅此处。

除了创建自己的圆形库之外,还有其他方法可以解决这个问题吗?


解决方案 1:

我无法控制它的存储方式,但至少格式正确:

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

解决方案 2:

即使不进行四舍五入,格式化也能正确工作:

"%.1f" % n

解决方案 3:

如果您使用 Decimal 模块,则可以不使用“round”函数进行近似。以下是我在编写货币应用程序时一直使用的舍入方法:

from decimal import Decimal, ROUND_UP

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

这将返回一个十进制数,即 16.20。

解决方案 4:

round(5.59, 1)运行正常。问题是 5.6 无法用二进制浮点精确表示。

>>> 5.6
5.5999999999999996
>>> 

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

如果您需要的话, Python 有一个用于十进制算术的模块。

解决方案 5:

str(round(n, 1))如果你这样做而不是仅仅这样做,则会得到“5.6” round(n, 1)

解决方案 6:

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

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

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

不过,Jimmy的回答更好。

解决方案 7:

看一下Decimal 模块

十进制“基于浮点模型,该模型的设计充分考虑了人们的需要,并且必然有一个至关重要的指导原则——计算机必须提供一种与人们在学校学习的算术相同的算术。”——摘自十进制算术规范。

十进制数可以精确表示。相比之下,像 1.1 和 2.2 这样的数字在二进制浮点数中没有精确的表示。最终用户通常不会期望 1.1 + 2.2 显示为 3.3000000000000003,就像二进制浮点数那样。

Decimal 提供的运算类型使得编写需要浮点运算的应用程序变得容易,并且需要以人类可读的格式呈现这些结果,例如会计。

解决方案 8:

浮点数运算容易出现轻微但令人烦恼的精度误差。如果您可以使用整数或定点,则可以保证精度。

解决方案 9:

这确实是个大问题。试试以下代码:

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 的幂的分数的最接近的有限和。

解决方案 10:

printf那个傻瓜。

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

解决方案 11:

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:

另一个可能的选择是:

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)

解决方案 13:

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

mystring = "%.2f" % 5.5999

解决方案 14:

我正在做:

int(round( x , 0))

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

所以

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

我认为这个答案比格式化字符串效果更好,并且对我来说使用 round 函数也更有意义。

解决方案 15:

完美运作

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

解决方案 16:

代码:

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

解决方案 17:

问题只出现在最后一位数字为 5 时。例如,0.045 在内部存储为 0.0449999999999999... 您可以简单地将最后一位数字增加到 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

解决方案 18:

我看到这里四舍五入失败了。如果你想将这两个数字四舍五入到小数点后一位,该怎么办?23.45 23.55 我所学的知识是,四舍五入后你应该得到:23.4 23.6 “规则”是,如果前一个数字是奇数,则应该向上舍入,如果前一个数字是偶数,则不应该向上舍入。python 中的 round 函数只是截断了 5。

解决方案 19:

使用 round() 时我遇到了同样的错误。现在,我使用 ceil() 或 floor(),如下所示:

import math
x = 76.5
x_str = str(x)
dot_index = x_str.index('.')
if(int(x_str[dot_index+1:]) >= 5):
  x = math.ceil(x)
else:
  x = math.floor(x)

解决方案 20:

这是一种将浮点数四舍五入到任意小数位的简单方法,并且它在 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

解决方案 21:

那么:

round(n,1)+epsilon
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2379  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1510  
  PLM(产品生命周期管理)系统在企业项目管理中扮演着至关重要的角色,它能够整合产品从概念设计到退役的全流程信息,提升协同效率,降低成本。然而,项目范围蔓延是项目管理过程中常见且棘手的问题,在PLM系统环境下也不例外。范围蔓延可能导致项目进度延迟、成本超支、质量下降等一系列不良后果,严重影响项目的成功交付。因此,如何在P...
plm项目经理是做什么   16  
  PLM(产品生命周期管理)系统在现代企业的产品研发与管理过程中扮演着至关重要的角色。它不仅仅是一个管理产品数据的工具,更能在利益相关者分析以及沟通矩阵设计方面提供强大的支持。通过合理运用PLM系统,企业能够更好地识别、理解和管理与产品相关的各类利益相关者,构建高效的沟通机制,从而提升产品开发的效率与质量,增强企业的市场...
plm是什么   20  
  PLM(产品生命周期管理)项目管理对于企业产品的全生命周期规划、执行与监控至关重要。在项目推进过程中,监控进度偏差是确保项目按时、按质量完成的关键环节。五维健康检查指标体系为有效监控PLM项目进度偏差提供了全面且系统的方法,涵盖了项目的多个关键维度,有助于及时发现问题并采取针对性措施。需求维度:精准把握项目基石需求维度...
plm项目管理软件   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用