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

1527 python floating-point precision rounding

我希望a四舍五入到13.95.

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Run Code Online (Sandbox Code Playgroud)

round功能不像我预期的那样工作.

Rex*_*gan 1523

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

在浮点数中,您的圆形版本是相同的数字.由于计算机是二进制的,它们将浮点数存储为整数,然后将其除以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("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999
Run Code Online (Sandbox Code Playgroud)

如果您只有两位小数,那么您有几个更好的选择:1)使用整数并以美分存储值,而不是美元,然后除以100转换为美元.2)或使用十进制的固定点数.

  • @Christian存储的值与您显示该值的方式之间存在根本区别.格式化输出应该允许您根据需要添加填充,以及添加逗号分隔符等. (24认同)
  • 为什么人们总是在浮点舍入上采用货币?有时你只是想以较低的精度工作. (17认同)
  • 值得一提的是``%.2f'%round(a,2)`你不仅可以放在printf中,还可以输入像`str()这样的东西 (16认同)
  • @radtek:你没从字面上要求一个解释.最简单的解决方案确实是使用`Decimal`,那就是在这个答案提出的解决方案之一.另一个是转换的数量为整数并使用整数运算.这两种方法也出现在其他的答案和评论. (10认同)
  • @radtek:您需要了解二进制值(类型为"float")只是十进制数的最接近可用近似值(您熟悉的是人类).没有这样的(有限可表示的)二进制值为0.245.它根本不存在,数学上**不能存在.最接近0.245的二进制值略小于**0.245,因此自然它向下舍入.同样地,二进制中没有0.225这样的东西,但是最接近0.225的二进制值稍微大于**0.225,所以自然它会向上舍入. (6认同)
  • 注意格式0是python 2.7或3.1中不需要的位置参数,我认为它是格式的一部分并得到奇怪的结果:)("{:.2f}".format(a) (2认同)
  • 顺便说一句,从 Python 3.6 开始,我们可以使用 f 字符串:`f"Result is {result:.2f}"` (2认同)
  • @MahdiAmrollahi:计算机有位。他们无法存储“实数”。他们只是将各个位组合在一起并以传统方式解释它们。对于整数来说,这相当简单(许多位都是以 2 为基数的数字)。但是只有 0 和 1 就无法存储“真实值”,特别是当真实值是无理值(例如 pi)时。IEEE-754 算术(Python 中的“float”,C/C++/C# 中的“float”/“double”)高效且“足够接近”。存在更精确的选项(“fractions.Fraction”、“decimal.Decimal”;后者使用与您要求的类似的存储格式),但它们更慢、更大。 (2认同)

Xol*_*lve 541

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

您可以这样做:

"{0:.2f}".format(13.949999999999999)
Run Code Online (Sandbox Code Playgroud)

请注意,上面返回一个字符串.为了得到浮点数,只需用float(...):

float("{0:.2f}".format(13.949999999999999))
Run Code Online (Sandbox Code Playgroud)

请注意,换行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
Run Code Online (Sandbox Code Playgroud)

  • 要添加逗号你也可以``{0:,.2f}'.format(1333.949999999)`打印`'1,333.95'`. (15认同)
  • @JossefHarush你可以用float()包装它,但你还没有获得任何东西.现在你又有了一个漂浮物,同样的不精确.13.9499999999999和13.95是相同的浮点数. (5认同)
  • @NedBatchelder:我同意它们是相同的,但是这会将浮点数限制为两个小数点:) (4认同)
  • 顺便说一下,从Python 3.6开始,我们可以使用f字符串:`f“ Result is {result:.2f}”` (3认同)

chr*_*sen 261

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

例:

>>> round(14.22222223, 2)
14.22
Run Code Online (Sandbox Code Playgroud)

查看文档.

  • 请注意,如果您尝试使用此方法打印数字(例如 1.00000),则无论您指定多少个小数点,它都只会打印出 1.0。 (3认同)
  • 例如,如果您尝试将值 2.675 四舍五入到小数点后两位,则会得到“>>> round(2.675, 2) 2.67” https://docs.python.org/2/tutorial/floatingpoint.html (2认同)
  • 从Python 3文档页面:`注意float()的round()行为可能令人惊讶:例如,round(2.675,2)给出2.67,而不是预期的2.68。这不是错误:这是由于大多数十进制小数不能完全表示为浮点数的结果。 (2认同)

gra*_*ski 136

我觉得最简单的方法是使用该format()功能.

例如:

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

13.95
Run Code Online (Sandbox Code Playgroud)

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


小智 93

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

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
Run Code Online (Sandbox Code Playgroud)

最后,虽然也许最重要的是,如果你想要精确的数学,那么你根本不需要花车.通常的例子是处理货币并将"美分"存储为整数.


Ale*_*nko 89

使用

print"{:.2f}".format(a)
Run Code Online (Sandbox Code Playgroud)

代替

print"{0:.2f}".format(a)
Run Code Online (Sandbox Code Playgroud)

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

  • 这是无稽之谈。给出的两个语句在Python 2.7上的行为相同,并且仅第二条语句在Python 2.6上有效。(这两个语句在Python 3或Python <2.6中均无效。)第一种形式除了简洁以外没有任何优势。 (2认同)
  • 对于Python 3,您只需添加括号print(...).在他们内部我写的都是对的. (2认同)
  • 如果您有两个变量,您将在打印后("{0:.2f} {1:.2f}".format(a,b)) (2认同)

ax0*_*03d 70

请尝试以下代码:

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

  • 如果`round()`不像OP提到的那样工作,那么@interjay是必要的. (4认同)
  • 如果采用这种方法,则应添加0.5以获得更准确的表示.int(a*100 + 0.5)/ 100.0; 使用math.ceil是另一种选择. (3认同)
  • @ShashankSawant:嗯,首先,所呈现的答案不是圆的,它会截断.在最后添加一半的建议将会循环,但是这样做首先只使用`round`函数没有任何好处.另一方面,因为这个解决方案仍然使用浮点,OP的原始问题仍然存在,即使对于这个"解决方案"的"更正"版本也是如此. (3认同)
  • -1,这只是`round`函数的不必要的重新实现(在问题中使用). (2认同)

A.J*_*.J. 52

使用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)
Run Code Online (Sandbox Code Playgroud)

但请注意,对于3以上的Python版本(例如3.2或3.3),选项2是首选.

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

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

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


hyn*_*cer 50

TLDR;)

输入/输出的舍入问题已由Python 2.7.03.1明确解决.

无限测试:

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+ :-)
Run Code Online (Sandbox Code Playgroud)

文档

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

现在,在大多数平台上,浮点数和字符串之间的转换正确舍入.这些转换发生在许多不同的地方:浮点数上的str()和复数; 浮动和复杂的构造函数; 数字格式; 序列化使用和反序列化浮子和复数str -> float() -> repr() -> float() ...,Decimal -> float -> str -> Decimalstr()模块; 在Python代码中解析float和imaginary文字; 和十进制到浮点转换.

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

相关问题


更多信息::marshal Python 2.7之前的格式与当前类似pickle.两种类型都使用相同的64位IEEE 754双精度和52位尾数.一个很大的区别是json经常使用过多的十进制数格式化,因此不会丢失任何位,但13.949999999999999和13.950000000000001之间不存在有效的IEEE 754编号.结果不好,转换float不可逆.另一方面:numpy.float64格式化,以便每个数字都很重要; 序列没有间隙,转换是可逆的.简单地说:如果您可能有一个numpy.float64数字,请将其转换为普通浮点数,以便为人类而不是数字处理器进行格式化,否则Python 2.7+不再需要它.


Gre*_*ill 48

您可以修改输出格式:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Run Code Online (Sandbox Code Playgroud)


Irf*_*ani 40

float_number = 12.234325335563
round(float_number, 2)
Run Code Online (Sandbox Code Playgroud)

这将返回;

12.23
Run Code Online (Sandbox Code Playgroud)

解释:

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

  • 但是如果我们说 0.093,你是如何获得额外的 0 的呢?这给了我 0.1 作为答案 (2认同)

Asa*_*oor 36

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

print(format(14.4499923, '.2f')) // output is 14.45
Run Code Online (Sandbox Code Playgroud)

  • 这将返回字符串 (4认同)

Mat*_*her 34

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

>>> f'{a:.2f}'
Run Code Online (Sandbox Code Playgroud)

它也可以用更长的例子,运算符而不需要parens:

>>> print(f'Completed in {time.time() - start:.2f}s')
Run Code Online (Sandbox Code Playgroud)

  • 现在已经是 2020 年底了,但情况仍然如此。 (7认同)

Sha*_*ngh 28

在Python 2.7中:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
Run Code Online (Sandbox Code Playgroud)


nos*_*klo 22

Python教程有一个名为Floating Point Arithmetic的附录:问题和限制.阅读.它解释了发生了什么以及为什么Python正在发挥最大作用.它甚至有一个与你相匹配的例子.让我引用一下:

>>> 0.1
0.10000000000000001
Run Code Online (Sandbox Code Playgroud)

您可能想要使用该round() 功能将其切换回您期望的单个数字.但这没有区别:

>>> round(0.1, 1)
0.10000000000000001
Run Code Online (Sandbox Code Playgroud)

问题是存储的二进制浮点值“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
Run Code Online (Sandbox Code Playgroud)

解决问题的另一种方法是使用该decimal模块.


小智 21

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

x = 1.090675765757
g = float("{:.2f}".format(x))
print(g)
Run Code Online (Sandbox Code Playgroud)

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

x = 1.090675765757
g =  round(x, 2)
print(g)
Run Code Online (Sandbox Code Playgroud)

  • 问题明确指出,round 方法没有达到他想要的效果。检查[此答案](/sf/answers/31894411/)以获取有关原因的更多信息 (2认同)

tot*_*ico 16

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

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')
Run Code Online (Sandbox Code Playgroud)

将显示 result: 2.35


小智 14

对于原始Python:

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

a = 13.949999999999999
format(a, '.2f')
Run Code Online (Sandbox Code Playgroud)

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

a = 13.949999999999999
round(float(a), 2)
or
float(format(a, '.2f'))
Run Code Online (Sandbox Code Playgroud)


HUA*_*UAH 13

它正在完成你告诉它要做的事情并且正常工作.阅读有关浮点混淆的更多信息,也可以尝试使用十进制对象.


Sia*_*and 8

为了修复类型动态语言(如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
Run Code Online (Sandbox Code Playgroud)

您还可以使用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')
Run Code Online (Sandbox Code Playgroud)


Pra*_*mar 8

简单的解决方案就在这里

value = 5.34343
rounded_value = round(value, 2) # 5.34
Run Code Online (Sandbox Code Playgroud)

  • 这里有很多不必要的东西。`8/3` 已经是 `float` 类型,所以 `float` 调用没有任何用处。直接调用 dunder 方法有点奇怪 - 相反,只需调用委托给这些 dunder 方法的函数即可。因此,拼写第一行的更好方法是“value = round(8/3, 2)”。那时,您并没有真正添加其他答案中尚未添加的任何内容。 (2认同)

Gus*_*eta 7

像这样的 lambda 函数怎么样:

arred = lambda x,n : x*(10**n)//1/(10**n)
Run Code Online (Sandbox Code Playgroud)

这样你就可以这样做:

arred(3.141591657,2)
Run Code Online (Sandbox Code Playgroud)

并得到

3.14
Run Code Online (Sandbox Code Playgroud)


Jon*_*n L 7

结合使用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')
Run Code Online (Sandbox Code Playgroud)


Mik*_*keL 6

orig_float = 232569 / 16000.0
Run Code Online (Sandbox Code Playgroud)

14.5355625

short_float = float("{:.2f}".format(orig_float)) 
Run Code Online (Sandbox Code Playgroud)

14.54


wea*_*ing 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)
Run Code Online (Sandbox Code Playgroud)

结果:

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'
Run Code Online (Sandbox Code Playgroud)


Sła*_*art 6

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

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

    d=十进制(10000000.0000009)

实现四舍五入:

   d.quantize(Decimal('0.01'))
Run Code Online (Sandbox Code Playgroud)

将结果与 Decimal('10000000.00')

  1. 使以上干燥:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))
Run Code Online (Sandbox Code Playgroud)

或者

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

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


小智 6

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

float(format(num, '.2f'))
Run Code Online (Sandbox Code Playgroud)

注意:我们将数字转换为浮点数,因为 format 方法返回一个字符串。


Yog*_*dav 5

如果你想处理金钱,请使用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
Run Code Online (Sandbox Code Playgroud)