将浮点数限制为小数点后两位

2024-11-19 08:38:00
admin
原创
12
摘要:问题描述:我希望a四舍五入为13.95。我尝试使用round,但得到:>>> a 13.949999999999999 >>> round(a, 2) 13.949999999999999 对于标准库 Decimal 类的类似问题,请参阅如何格式化小数以始终显示 2 位小数...

问题描述:

我希望a四舍五入为13.95。我尝试使用round,但得到:

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

对于标准库 Decimal 类的类似问题,请参阅如何格式化小数以始终显示 2 位小数?。


解决方案 1:

您遇到了浮点数的老问题,即并非所有数字都能准确表示。命令行只是向您显示内存中的完整浮点形式。

使用浮点表示法,舍入后的版本是相同的数字。由于计算机是二进制的,它们将浮点数存储为整数,然后将其除以 2 的幂,因此 13.95 将以类似于 125650429603636838/(2**53) 的方式表示。

双精度数具有 53 位(16 位)精度,而常规浮点数具有 24 位(8 位)精度。Python中的浮点类型使用双精度来存储值。

例如,

>>> 125650429603636838/(2**53)
13.949999999999999

>>> 234042163/(2**24)
13.949999988079071

>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

如果您只需要两位小数(例如,显示货币值),那么您有几个更好的选择:

  1. 使用整数并以美分而不是美元为单位存储值,然后除以 100 转换为美元。

  2. 或者使用像十进制这样的定点数。

解决方案 2:

有新的格式规范,字符串格式规范迷你语言

您可以做同样的事情:

"{:.2f}".format(13.949999999999999)

注 1:以上代码返回一个字符串。为了获取浮点数,只需用以下代码包装float(...)

float("{:.2f}".format(13.949999999999999))

注 2:包装float()不会改变任何内容:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True

解决方案 3:

内置round()功能在 Python 2.7 或更高版本中运行良好。

例子:

>>> round(14.22222223, 2)
14.22

查看文档。

解决方案 4:

让我举一个 Python 3.6 的f-string /template-string 格式的例子,我认为它非常简洁:

>>> f'{a:.2f}'

它也适用于较长的示例,使用运算符并且不需要括号:

>>> print(f'Completed in {time.time() - start:.2f}s')

解决方案 5:

我觉得最简单的方法是使用format()函数。

例如:

a = 13.949999999999999
format(a, '.2f')

13.95

这将生成一个浮点数作为四舍五入到小数点后两位的字符串。

解决方案 6:

大多数数字无法用浮点数精确表示。如果您想要对数字进行四舍五入,因为这是您的数学公式或算法所要求的,那么您需要使用 round。如果您只是想将显示限制在一定的精度,那么甚至不要使用 round,只需将其格式化为该字符串即可。(如果您想使用某种替代的舍入方法来显示它,并且有很多,那么您需要混合使用这两种方法。)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

最后,但也许最重要的是,如果您想要精确的数学运算,那么您根本不需要浮点数。通常的例子是处理金钱并将“美分”存储为整数。

解决方案 7:

使用

print"{:.2f}".format(a)

而不是

print"{0:.2f}".format(a)

因为后者在尝试输出多个变量时可能会导致输出错误(见注释)。

解决方案 8:

长话短说;)

Python 3.1已经彻底解决了输入和输出的舍入问题,并且该修复也已移植到 Python 2.7.0。

四舍五入的数字可以在浮点数和字符串之间来回转换

str -> float() -> repr() -> float() ...或者Decimal -> float -> str -> Decimal

>>> 0.3
0.3
>>> float(repr(0.3)) == 0.3
True

Decimal不再需要类型来存储。

算术运算的结果必须再次舍入,因为舍入误差可能会累积到比解析一个数字后更大的不准确性。改进的repr()算法(Python >= 3.1,>= 2.7.0)没有解决这个问题:

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1, 0.2, 0.3
(0.1, 0.2, 0.3)

在 Python 2.7x 以下版本和 3.1 以下版本中,输出字符串函数str(float(...))被四舍五入为 12 位有效数字,以防止出现与未修复的 repr() 输出类似的过多无效数字。在减去非常相似的数字后,这仍然不够,并且在其他操作之后四舍五入过多。尽管 repr() 是固定的,但 Python 2.7 和 3.1 使用相同长度的 str()。即使使用修复后的 Python,某些旧版本的 Numpy 也存在过多的无效数字。当前的 Numpy 已修复。Python 版本 >= 3.2 具有 str() 和 repr() 函数的相同结果,并且还具有 Numpy 中类似函数的输出。


测试

import random
from decimal import Decimal
for _ in range(1000000):
    x = random.random()
    assert x == float(repr(x)) == float(Decimal(repr(x)))  # Reversible repr()
    assert str(x) == repr(x)
    assert len(repr(round(x, 12))) <= 14         # no excessive decimal places.

文档

请参阅发行说明 Python 2.7 - Other Language Changes第四段:

现在,大多数平台上浮点数和字符串之间的转换都已正确舍入marshal。这些转换发生在许多不同的地方:浮点数和复数上的 str();浮点数和复数构造函数;数字格式化;使用、picklejson模块序列化和反序列化浮点数和复数;解析 Python 代码中的浮点数和虚数文字;以及十进制到浮点数的转换。

与此相关,浮点数 x 的repr()现在基于最短十进制字符串返回结果,该字符串保证在正确舍入(使用四舍五入为偶数的舍入模式)的情况下舍入回 x。以前,它基于将 x 四舍五入为 17 位十进制数字给出一个字符串。

相关问题


更多信息: Python 2.7 之前的格式float与当前的类似numpy.float64。两种类型都使用相同的 64 位IEEE 754双精度和 52 位尾数。一个很大的区别是,它np.float64.__repr__经常使用过多的十进制数进行格式化,以便不会丢失任何位,但是在 13.949999999999999 和 13.950000000000001 之间不存在有效的 IEEE 754 数字。结果并不好,并且repr(float(number_as_string))使用 numpy 无法进行可逆转换。另一方面:float.__repr__它的格式使得每个数字都很重要;序列没有间隙,转换是可逆的。简单来说:如果你有一个 numpy.float64 数字,请将其转换为普通浮点数以便为人类格式化,而不是为数字处理器格式化,否则使用 Python 2.7+ 就不需要做更多的事情了。

解决方案 9:

尝试下面的代码:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

解决方案 10:

使用:

float_number = 12.234325335563
round(float_number, 2)

这将返回;

12.23

解释:

round函数接受两个参数:要四舍五入的数字和要返回的小数位数。这里我返回了两位小数。

解决方案 11:

您可以修改输出格式:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

解决方案 12:

对于 Python <3(例如 2.6 或 2.7),有两种方法可以实现。

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

但请注意,对于 Python 3 以上的版本(例如 3.2 或 3.3),最好使用选项二。

有关第二种选择的更多信息,我建议参阅Python 文档中有关字符串格式的链接。

有关选项 1 的更多信息,请访问此链接,其中包含有关各种标志的信息。

参考:将浮点数转换为一定精度,然后复制到字符串

解决方案 13:

您可以使用格式运算符在 Python 中将值四舍五入到小数点后两位:

print(format(14.4499923, '.2f')) // The output is 14.45

解决方案 14:

正如Matt 指出的那样,Python 3.6 提供了f 字符串,并且它们还可以使用嵌套参数:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

将显示result: 2.35

解决方案 15:

在 Python 2.7 中:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

解决方案 16:

我们有多种选择来做到这一点:

选项 1:

x = 1.090675765757
g = float("{:.2f}".format(x))
print(g)

选项2:内置的round()支持Python 2.7或更高版本。

x = 1.090675765757
g = round(x, 2)
print(g)

解决方案 17:

Python 教程中有一篇附录,名为《浮点运算:问题和限制》。请阅读。它解释了发生了什么,以及为什么 Python 能做到最好。它甚至有一个与你的例子相匹配的例子。让我引用一点:

>>> 0.1
0.10000000000000001

您可能想使用该round()
函数将其缩短为期望的个位数。但这并没有什么区别:

>>> round(0.1, 1)
0.10000000000000001

问题在于,存储的二进制浮点值“0.1”
已经是 的最佳二进制近似值1/10,因此尝试再次对其进行舍入无法使其变得更好:它已经是最好的了。

另一个结果是,由于0.1
不完全是1/10,因此对 的十个值进行求和也0.1可能无法完全得到
1.0

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

解决您的问题的一个替代方法是使用decimal模块。

解决方案 18:

结合使用 Decimal 对象和 round() 方法。

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')

解决方案 19:

对于原始 Python:

对于浮点数到字符串转换2个小数点:

a = 13.949999999999999
format(a, '.2f')

对于浮点数到浮点数转换2位小数:

a = 13.949999999999999
round(float(a), 2)
or
float(format(a, '.2f'))

解决方案 20:

它完全按照您的要求执行,并且工作正常。阅读有关浮点混淆的更多信息,也许可以尝试使用十进制对象。

解决方案 21:

from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

结果:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'

解决方案 22:

简单的解决方案就在这里

value = 5.34343
rounded_value = round(value, 2) # 5.34

解决方案 23:

使用如下 lambda 函数:

arred = lambda x,n : x*(10**n)//1/(10**n)

这样你就可以这样做:

arred(3.141591657, 2)

并得到

3.14

解决方案 24:

它很简单,例如:

  1. 使用十进制模块进行快速正确舍入的十进制浮点运算:

 d = Decimal(10000000.0000009)

实现舍入:

 d.quantize(Decimal('0.01'))

将导致Decimal('10000000.00')

  1. 使上述内容干燥:

def round_decimal(number, exponent='0.01'):
    decimal_value = Decimal(number)
    return decimal_value.quantize(Decimal(exponent))

或者

def round_decimal(number, decimal_places=2):
    decimal_value = Decimal(number)
    return decimal_value.quantize(Decimal(10) ** -decimal_places)

PS:批评别人:格式化不是四舍五入。

解决方案 25:

orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54

解决方案 26:

为了修复 Python 和 JavaScript 等动态类型语言中的浮点数,我使用这种技术

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

您还可以使用十进制,如下所示:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

解决方案 27:

以下是使用格式化函数的简单解决方案。

float(format(num, '.2f'))

注意:我们正在将数字转换为浮点数,因为格式方法返回的是字符串。

解决方案 28:

如果要处理金钱,请使用 Python十进制模块:

from decimal import Decimal, ROUND_HALF_UP

# 'amount' can be integer, string, tuple, float, or another Decimal object
def to_money(amount) -> Decimal:
    money = Decimal(amount).quantize(Decimal('.00'), rounding=ROUND_HALF_UP)
    return money

解决方案 29:

lambda x, n:int(x*10^n + 0.5)/10^n

多年来一直为我使用多种语言工作。

解决方案 30:

要将数字四舍五入为某个分辨率,最好的方法是以下方法,它可以适用于任何分辨率(0.01 表示两位小数,甚至其他步骤):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用