Limiting floats to two decimal points
我要把EDOCX1[0]四舍五入到13.95。
1 2 3 4 | >>> a 13.949999999999999 >>> round(a, 2) 13.949999999999999 |
您遇到了浮点数的旧问题,所有的数字都无法表示。命令行只是显示内存中完整的浮点形式。
在浮点中,四舍五入的版本是相同的数字。由于计算机是二进制的,它们将浮点数存储为整数,然后除以2的幂,因此13.95将以类似于125650429603636838/(2**53)的方式表示。
双精度数的精度为53位(16位),常规浮点数的精度为24位(8位)。python中的浮点使用双精度存储值。
例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | >>> 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)或使用小数等固定点号。
有新的格式规范,字符串格式规范迷你语言:
您可以这样做:
1 | "{0:.2f}".format(13.949999999999999) |
注意,上面返回的是一个字符串。为了获得浮点数,只需用
1 | float("{0:.2f}".format(13.949999999999999)) |
注意,用EDOCX1[2]包装不会改变任何东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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 |
内置的
例子:
1 2 | >>> round(14.22222223, 2) 14.22 |
查看文档。
我觉得最简单的方法是使用
例如:
1 2 3 4 | a = 13.949999999999999 format(a, '.2f') 13.95 |
这将产生一个浮点数作为一个四舍五入为两个小数点的字符串。
大多数数字不能精确地用浮点数表示。如果您想对数字进行四舍五入,因为这正是您的数学公式或算法所要求的,那么您需要使用四舍五入。如果您只想将显示限制到一定的精度,那么甚至不要使用圆形,而是将其格式化为该字符串。(如果您想用其他舍入方法显示它,并且有吨,那么您需要混合这两种方法。)
1 2 3 4 | >>>"%.2f" % 3.14159 '3.14' >>>"%.2f" % 13.9499999 '13.95' |
最后,也许最重要的是,如果你想要精确的数学,那么你根本不想要浮点数。通常的例子是处理货币并将"美分"存储为整数。
使用
1 | print"{:.2f}".format(a) |
而不是
1 | print"{0:.2f}".format(a) |
因为当尝试输出多个变量时,后者可能会导致输出错误(参见注释)。
请尝试以下代码:
1 2 3 4 | >>> 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),有两种方法可以做到这一点。
1 2 3 4 5 | # 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。
有关选项2的更多信息,我建议使用Python文档中关于字符串格式的链接。
关于选项1的更多信息,这个链接就足够了,并且有关于各种标志的信息。
引用:将浮点数转换为某个精度,然后复制到字符串
您可以修改输出格式:
1 2 3 4 5 | >>> a = 13.95 >>> a 13.949999999999999 >>> print"%.2f" % a 13.95 |
TLDR;
python 2.7.0和3.1最终解决了输入输出的舍入问题。
正确的四舍五入数字可以来回转换:
(当然,可能需要对整数的加或减结果进行四舍五入,以消除累积的最后一位错误。一个明确的十进制算法仍然很方便,但是如果不需要极端的精度或极端的连续算术运算,由
无限测试:
1 2 3 4 5 6 7 8 9 10 | 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-其他语言更改第四段:
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 andjson 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.
相关问题
更多信息:在python 2.7之前,
在Python 2.7中:
1 2 3 | a = 13.949999999999999 output = float("%0.2f"%a) print output |
这里似乎还没有人提到它,所以让我举一个用python 3.6的f-string/template-string格式的例子,我认为这个格式非常简洁:
1 | >>> f'{a:.2f}' |
它也适用于较长的示例,也适用于运算符,不需要parens:
1 | >>> print(f'Completed in {time.time() - start:.2f}s') |
Python教程有一个称为浮点算术的附录:问题和限制。读它。它解释了正在发生的事情以及为什么python正在尽其所能。它甚至还有一个与您的相匹配的例子。让我引用一点:
1
2 >>> 0.1
0.10000000000000001you may be tempted to use the
round()
function to chop it back to the single
digit you expect. But that makes no
difference:
1
2 >>> round(0.1, 1)
0.10000000000000001The problem is that the binary
floating-point value stored for"0.1"
was already the best possible binary
approximation to1/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 exactly1/10 , summing ten
values of0.1 may not yield exactly
1.0 , either:
1
2
3
4
5
6 >>> sum = 0.0
>>> for i in range(10):
... sum += 0.1
...
>>> sum
0.99999999999999989
解决问题的另一种方法是使用
它做的正是你告诉它做的,并且工作正常。请阅读有关浮点混淆的更多信息,并尝试使用十进制对象。
正如@matt指出的那样,python 3.6提供了F字符串,它们还可以使用嵌套参数:
1 2 3 4 5 | value = 2.34558 precision = 2 width = 4 print(f'result: {value:{width}.{precision}f}') |
显示
在python中,可以使用格式运算符将值四舍五入到小数点后2位:
1 | print(format(14.4499923, '.2f')) // output is 14.45 |
为了修复类型动态语言(如python和javascript)中的浮点,我使用这种技术
1 2 3 4 5 6 7 8 9 | # 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 |
您还可以使用十进制,如下所示:
1 2 3 4 5 6 7 8 | 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') |
1 | orig_float = 232569 / 16000.0 |
14.5355625
1 | short_float = float("{:.2f}".format(orig_float)) |
14.54
1 2 3 4 5 6 7 8 9 | 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) |
结果:
1 2 3 4 5 6 7 8 9 10 11 | 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' |
它很简单,比如1,2,3:
使用十进制模块快速正确舍入十进制浮点运算:
D=小数(10000000.0000009)
要实现舍入:
1 | d.quantize(Decimal('0.01')) |
将与
1 2 3 | def round_decimal(number, exponent='0.01'): decimal_value = Decimal(number) return decimal_value.quantize(Decimal(exponent)) |
或
1 2 3 | def round_decimal(number, decimal_places=2): decimal_value = Decimal(number) return decimal_value.quantize(Decimal(10) ** -decimal_places) |
附:批评他人:格式不是四舍五入。
要将数字四舍五入为一个分辨率,最好的方法是以下方法,它可以与任何分辨率一起使用(两个小数点或其他步骤为0.01):
1 2 3 4 5 6 7 8 9 10 11 | >>> 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 |
我使用的方法是字符串切片。它相对简单快捷。
首先,将浮点转换为字符串,然后选择希望的长度。
1 | float = str(float)[:5] |
在上面的单行中,我们将值转换为一个字符串,然后只将该字符串保留为前四位数字或字符(包括前四位数字或字符)。
希望有帮助!