将浮点数限制为两个小数点

时间:2009-01-18 18:16:41

标签: python floating-point rounding precision

我希望a四舍五入为 13.95

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

round功能无法按预期工作。

29 个答案:

答案 0 :(得分:1377)

您遇到了浮点数的旧问题,无法表示所有数字。命令行只显示内存中的完整浮点形式。

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

双精度数字具有53位(16位)的精度,而常规浮点数具有24位(8位)的精度。用于存储值的floating point in Python uses double precision

例如,

  >>> 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)或使用固定点数,如decimal

答案 1 :(得分:495)

有新格式规范,String Format Specification Mini-Language

您可以这样做:

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

注意以上返回一个字符串。为了得到浮点数,只需用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

答案 2 :(得分:227)

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

示例:

>>> round(14.22222223, 2)
14.22

查看http://jumptuck.com/2009/01/09/wordpress-on-non-standard-port-not-port-80/

答案 3 :(得分:131)

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

例如:

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

13.95

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

答案 4 :(得分:89)

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

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

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

答案 5 :(得分:79)

使用

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

而不是

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

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

答案 6 :(得分:69)

尝试以下代码:

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

答案 7 :(得分:51)

使用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为preferred

有关选项二的更多信息,我建议string formatting from the Python documentation上的此链接。

有关选项一的更多信息,this link will suffice and has information on the various flags

参考: Convert floating point number to a certain precision, and then copy to string

答案 8 :(得分:44)

您可以修改输出格式:

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

答案 9 :(得分:39)

TLDR;)

输入/输出的舍入问题已经明确地通过Python 2.7.0 3.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+ :-)

文档

参见Release notes Python 2.7 - Other Language Changes第四段:

  在大多数平台上,浮点数和字符串之间的

转化次数现在正确舍入。这些转换发生在许多不同的地方:浮点数上的str()和复数;浮动和复杂的构造函数;数字格式;使用marshalpicklejson模块序列化和反序列化浮点数和复数;在Python代码中解析float和imaginary文字;和十进制到浮点数转换。

     

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

The related issue

更多信息: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 +不再需要它。

答案 10 :(得分:27)

在Python 2.7中:

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

答案 11 :(得分:24)

这里似乎没有人提到它,所以让我举一个Python 3.6的f-string / template-string格式的例子,我觉得它非常整洁:

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

对于更长的例子,它也适用于运算符而不需要parens:

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

答案 12 :(得分:20)

Python教程有一个名为 Floating Point Arithmetic: Issues and Limitations 的附录。阅读。它解释了发生了什么以及为什么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模块。

答案 13 :(得分:16)

您可以使用 format 运算符在python中将值四舍五入至小数点后两位:

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

答案 14 :(得分:12)

它正在完成你告诉它要做的事情并且正常工作。阅读有关floating point confusion的更多信息,并尝试使用decimal个对象。

答案 15 :(得分:11)

正如@Matt所指出的那样, Python 3.6提供了f-strings ,他们也可以使用 nested parameters

value = 2.34558
precision = 2
width = 4

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

将显示result: 2.35

答案 16 :(得分:7)

为了修复类型动态语言(如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

您还可以使用Decimal:

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')

答案 17 :(得分:7)

我们有多种选择可以做到这一点: 选项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)

答案 18 :(得分:6)

orig_float = 232569 / 16000.0
  

14.5355625

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

14.54

答案 19 :(得分:6)

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'

答案 20 :(得分:4)

float_number = 12.234325335563
round(float_number, 2)

这将返回;

12.23

round函数有两个参数; 要四舍五入的数字和要返回的小数位数。在这里,我返回了2个小数位数。

答案 21 :(得分:3)

就像1,2,3这样简单:

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

    d =十进制(10000000.0000009)

实现舍入:

   d.quantize(Decimal('0.01'))

将产生Decimal('10000000.00')

  1. 进行DRY以上的操作
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. 赞这个答案:)

PS:对他人的批评:格式不是四舍五入。

答案 22 :(得分:2)

像这样的lambda函数呢?

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

这样您就可以做到:

arred(3.141591657,2)

并获得

3.14

答案 23 :(得分:2)

我看到的答案不适用于float(52.15)情况。经过一些测试,有我正在使用的解决方案:

import decimal
        
def value_to_decimal(value, decimal_places):
    decimal.getcontext().rounding = decimal.ROUND_HALF_UP  # define rounding method
    return decimal.Decimal(str(float(value))).quantize(decimal.Decimal('1e-{}'.format(decimal_places)))

(“值”到浮点数然后是字符串的转换非常重要,这样,“值”可以是浮点,小数,整数或字符串类型!)

希望这对任何人都有帮助。

答案 24 :(得分:0)

结合使用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')

答案 25 :(得分:0)

lambda x,n:int(x * 10 n + .5)/ 10 n在许多语言中为我工作了很多年。

答案 26 :(得分:0)

如果您想赚钱,请使用python decimal模块

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

答案 27 :(得分:0)

这是使用格式函数的简单解决方案。

float(format(num, '.2f'))
<块引用>

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

答案 28 :(得分:-13)

我使用的方法是字符串切片。它相对快速而简单。

首先,将float转换为字符串,选择你想要的长度。

float = str(float)[:5]

在上面的单行中,我们已将值转换为字符串,然后将字符串仅保留为前四位数或字符(包括)。

希望有所帮助!