标签归档:precision

将浮点数限制为两位小数

问题:将浮点数限制为两位小数

我想a四舍五入到13.95

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

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

I want a to be rounded to 13.95.

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

The round function does not work the way I expected.


回答 0

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

使用浮点表示法,您的舍入版本为相同的数字。由于计算机是二进制的,因此它们将浮点数存储为整数,然后将其除以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("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

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

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

You are running into the old problem with floating point numbers that not all numbers can be represented exactly. The command line is just showing you the full floating point form from memory.

With floating point representation, your rounded version is the same number. Since computers are binary, they store floating point numbers as an integer and then divide it by a power of two so 13.95 will be represented in a similar fashion to 125650429603636838/(2**53).

Double precision numbers have 53 bits (16 digits) of precision and regular floats have 24 bits (8 digits) of precision. The floating point type in Python uses double precision to store the values.

For example,

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

If you are after only two decimal places (to display a currency value, for example), then you have a couple of better choices:

  1. Use integers and store values in cents, not dollars and then divide by 100 to convert to dollars.
  2. Or use a fixed point number like decimal.

回答 1

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

您可以执行以下操作:

"{:.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

There are new format specifications, String Format Specification Mini-Language:

You can do the same as:

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

Note 1: the above returns a string. In order to get as float, simply wrap with float(...):

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

Note 2: wrapping with float() doesn’t change anything:

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

回答 2

内建round()在Python 2.7或更高版本中工作正常。

例:

>>> round(14.22222223, 2)
14.22

查看文档

The built-in round() works just fine in Python 2.7 or later.

Example:

>>> round(14.22222223, 2)
14.22

Check out the documentation.


回答 3

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

例如:

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

13.95

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

I feel that the simplest approach is to use the format() function.

For example:

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

13.95

This produces a float number as a string rounded to two decimal points.


回答 4

采用

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

代替

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

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

Use

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

instead of

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

Because the latter may lead to output errors when trying to output multiple variables (see comments).


回答 5

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

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

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

Most numbers cannot be exactly represented in floats. If you want to round the number because that’s what your mathematical formula or algorithm requires, then you want to use round. If you just want to restrict the display to a certain precision, then don’t even use round and just format it as that string. (If you want to display it with some alternate rounding method, and there are tons, then you need to mix the two approaches.)

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

And lastly, though perhaps most importantly, if you want exact math then you don’t want floats at all. The usual example is dealing with money and to store ‘cents’ as an integer.


回答 6

请尝试以下代码:

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

Try the code below:

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

回答 7

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个十进制数字给出了一个字符串。

相关问题


详细信息:float Python 2.7之前的格式与当前相似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数字,请将其转换为普通float,以便为人类(而非数字处理器)格式化,否则Python 2.7+不再需要。

TLDR ;)

The rounding problem of input / output has been solved definitively by Python 2.7.0 and 3.1.

A correctly rounded number can be reversibly converted back and forth:
str -> float() -> repr() -> float() ... or Decimal -> float -> str -> Decimal
A Decimal type is not necessary for storage anymore.


(Naturally, it can be necessary to round a result of addition or subtraction of rounded numbers to eliminate the accumulated last bit errors. An explicit Decimal arithmetic can be still handy, but a conversion to string by str() (that is with rounding to 12 valid digits) is good enough usually if no extreme accuracy or no extreme number of successive arithmetic operations is required.)

Infinite test:

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+ :-)

Documentation

See the Release notes Python 2.7 – Other Language Changes the fourth paragraph:

Conversions between floating-point numbers and strings are now correctly rounded on most platforms. These conversions occur in many different places: str() on floats and complex numbers; the float and complex constructors; numeric formatting; serializing and de-serializing floats and complex numbers using the marshal, pickle and json modules; parsing of float and imaginary literals in Python code; and Decimal-to-float conversion.

Related to this, the repr() of a floating-point number x now returns a result based on the shortest decimal string that’s guaranteed to round back to x under correct rounding (with round-half-to-even rounding mode). Previously it gave a string based on rounding x to 17 decimal digits.

The related issue


More information: The formatting of float before Python 2.7 was similar to the current numpy.float64. Both types use the same 64 bit IEEE 754 double precision with 52 bit mantissa. A big difference is that np.float64.__repr__ is formatted frequently with an excessive decimal number so that no bit can be lost, but no valid IEEE 754 number exists between 13.949999999999999 and 13.950000000000001. The result is not nice and the conversion repr(float(number_as_string)) is not reversible with numpy. On the other hand: float.__repr__ is formatted so that every digit is important; the sequence is without gaps and the conversion is reversible. Simply: If you perhaps have a numpy.float64 number, convert it to normal float in order to be formatted for humans, not for numeric processors, otherwise nothing more is necessary with Python 2.7+.


回答 8

使用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文档中有关字符串格式的链接。

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

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

With Python < 3 (e.g. 2.6 or 2.7), there are two ways to do so.

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

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

But note that for Python versions above 3 (e.g. 3.2 or 3.3), option two is preferred.

For more information on option two, I suggest this link on string formatting from the Python documentation.

And for more information on option one, this link will suffice and has information on the various flags.

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


回答 9

您可以修改输出格式:

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

You can modify the output format:

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

回答 10

这里似乎还没有人提到它,所以让我举一个Python 3.6的f-string / template-string格式的例子,我认为它很简洁:

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

它也适用于较长的示例,不需要运算符,也不需要运算符:

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

Nobody here seems to have mentioned it yet, so let me give an example in Python 3.6’s f-string/template-string format, which I think is beautifully neat:

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

It works well with longer examples too, with operators and not needing parens:

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

回答 11

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

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

You can use format operator for rounding the value up to 2 decimal places in python:

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

回答 12

在Python 2.7中:

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

In Python 2.7:

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

回答 13

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模块。

The Python tutorial has an appendix called Floating Point Arithmetic: Issues and Limitations. Read it. It explains what is happening and why Python is doing its best. It has even an example that matches yours. Let me quote a bit:

>>> 0.1
0.10000000000000001

you may be tempted to use the round() function to chop it back to the single digit you expect. But that makes no difference:

>>> round(0.1, 1)
0.10000000000000001

The problem is that the binary floating-point value stored for “0.1” was already the best possible binary approximation to 1/10, so trying to round it again can’t make it better: it was already as good as it gets.

Another consequence is that since 0.1 is not exactly 1/10, summing ten values of 0.1 may not yield exactly 1.0, either:

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

One alternative and solution to your problems would be using the decimal module.


回答 14

正如@Matt所指出的,Python 3.6提供了f-strings,它们也可以使用嵌套参数

value = 2.34558
precision = 2
width = 4

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

将显示 result: 2.35

As @Matt pointed out, Python 3.6 provides f-strings, and they can also use nested parameters:

value = 2.34558
precision = 2
width = 4

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

which will display result: 2.35


回答 15

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

It’s doing exactly what you told it to do and is working correctly. Read more about floating point confusion and maybe try decimal objects instead.


回答 16

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

Use combination of Decimal object and round() method.

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

回答 17

为了固定类型动态语言(例如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')

For fixing the floating point in type-dynamic languages such as Python and JavaScript, I use this technique

# 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

You can also use Decimal as following:

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

回答 18

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

Results:

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'

回答 19

orig_float = 232569 / 16000.0

14.5355625

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

14.54

orig_float = 232569 / 16000.0

14.5355625

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

14.54


回答 20

像这样的lambda函数呢?

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

这样,您可以执行以下操作:

arred(3.141591657,2)

并得到

3.14

What about a lambda function like this:

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

This way you could just do:

arred(3.141591657,2)

and get

3.14

回答 21

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

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

    d =十进制(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)
  1. 支持这个答案:)

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

It’s simple like 1,2,3:

  1. use decimal module for fast correctly-rounded decimal floating point arithmetic:

    d=Decimal(10000000.0000009)

to achieve rounding:

   d.quantize(Decimal('0.01'))

will results with Decimal('10000000.00')

  1. make above 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. upvote this answer :)

PS: critique of others: formatting is not rounding.


回答 22

要将数字四舍五入为一种分辨率,最好的方法是使用以下方法,该方法可以在任何分辨率下工作(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

To round a number to a resolution, the best way is the following one, which can work with any resolution (0.01 for two decimals or even other steps):

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

回答 23

lambda x,n:int(x * 10 n + .5)/ 10 n已经为我使用多种语言提供多年的服务。

lambda x,n:int(x*10n+.5)/10n has worked for me for many years in many languages.


回答 24

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

首先,将float转换为字符串,然后选择所需的长度。

float = str(float)[:5]

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

希望有帮助!

The method I use is that of string slicing. It’s relatively quick and simple.

First, convert the float to a string, the choose the length you would like it to be.

float = str(float)[:5]

In the single line above, we’ve converted the value to a string, then kept the string only to its first four digits or characters (inclusive).

Hope that helps!