将浮点数限制为两位小数

我希望将a舍入为13.95

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

round功能不能按我预期的方式工作。

答案

您正在碰到浮点数的旧问题 ,即并非所有数字都可以准确表示。命令行只是向您显示内存中的完整浮点形式。

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

双精度数字的精度为 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("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

如果仅排两个小数位(例如,显示货币值),则有两个更好的选择:

  1. 使用整数并以美分而不是美元存储值,然后除以 100 转换为美元。
  2. 或者使用定点数,例如小数

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

您可以执行以下操作:

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

请注意 ,以上代码返回一个字符串。为了获得 float,只需用float(...)包装:

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

请注意 ,使用float()包装不会改变任何内容:

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

内置的round()在 Python 2.7 或更高版本中可以正常工作。

例:

>>> round(14.22222223, 2)
14.22

查看文档

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

例如:

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

13.95

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

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

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

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

采用

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

代替

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

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

请尝试以下代码:

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

使用 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)

但请注意,对于高于 3 的 Python 版本(例如 3.2 或 3.3), 首选选项 2。

有关选项二的更多信息,我建议使用 Python 文档中有关字符串格式的链接。

有关选项一的更多信息, 此链接就足够了,并且具有有关各种标志的信息

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

TLDR;)

输入 / 输出的舍入问题已由Python 2.7.03.1 彻底解决

正确舍入的数字可以可逆地来回转换:
str -> float() -> repr() -> float() ...Decimal -> float -> str -> Decimal
小数类型不再需要用于存储。


(自然地,可能有必要舍入四舍五入后的数字,以消除累积的最后一位误码的结果。显式的小数算法仍然很方便,但是可以通过str()转换为字符串(即舍入为如果不需要极高的精度或不需要极高数量的连续算术运算,通常 12 个有效数字就足够了。)

无限测试

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

文献资料

请参阅发行说明 Python 2.7 - 其他语言更改的第四段:

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

与此相关的是,浮点数 x 的repr()现在基于最短的十进制字符串返回一个结果,该字符串保证在正确的舍入(使用 “从一半到一半到四舍五入的舍入模式” 下) 可以返回到 x 。以前,它根据 x 舍入到 17 个十进制数字给出了一个字符串。

相关问题


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

您可以修改输出格式:

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