Answers:
您正在碰到浮点数的旧问题,即并非所有数字都可以准确表示。命令行只是向您显示内存中的完整浮点形式。
使用浮点表示法,您的舍入版本为相同的数字。由于计算机是二进制的,因此它们将浮点数存储为整数,然后将其除以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
如果仅排两个小数位(例如,显示货币值),则有两个更好的选择:
"%.2f" % round(a,2)
您不仅可以在printf中添加内容,而且还可以添加类似内容str()
float
)只是十进制数字(您作为人类所熟悉的)的最接近的可用近似值。没有这样的(绝对可表示的)二进制值0.245。它根本不存在,并且在数学上不存在。最接近0.245的二进制值略小于 0.245,因此自然会四舍五入。同样,作为二进制0.225没有这样的事情,但二进制值最接近0.225稍微大于 0.225,因此它自然四舍五入。
Decimal
,这是此答案中提出的解决方案之一。另一个是将您的数量转换为整数并使用整数算术。这两种方法也都出现在其他答案和评论中。
有新的格式规范,字符串格式规范迷你语言:
您可以执行以下操作:
"{:.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
'{0:,.2f}'.format(1333.949999999)
打印'1,333.95'
。
float()
;float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
round(2.16, 1)
给予2.2
为什么蟒蛇只是提供了一个truncate
FUNC
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
采用
print"{:.2f}".format(a)
代替
print"{0:.2f}".format(a)
因为后者在尝试输出多个变量时可能会导致输出错误(请参见注释)。
大多数数字不能用浮点数精确表示。如果要舍入该数字,因为这是您的数学公式或算法所需要的,那么您要使用舍入。如果您只想限制显示的精度,甚至不用舍入,只需将其格式化为该字符串即可。(如果要用其他替代的四舍五入方法显示它,并且有很多吨,则需要将两种方法混合使用。)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
最后,虽然也许是最重要的一点,但是如果您想要精确的数学运算,那么根本就不需要浮点数。通常的例子是处理货币并将“分”存储为整数。
请尝试以下代码:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
函数没有好处。另一方面,因为此解决方案仍使用浮点,所以即使对于此“解决方案”的“更正”版本,OP的原始问题仍然存在。
round
(在问题中使用过)。
round()
不能像前面提到的OP那样工作,则是必需的。
输入/输出的舍入问题已由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+ :-)
请参阅发行说明Python 2.7-其他语言更改的第四段:
现在,在大多数平台上都可以正确舍入浮点数和字符串之间的转换。这些转换发生在许多不同的地方:str()代表浮点数和复数;浮动和复杂的构造函数;数字格式;串行化,并使用反序列浮子和复数
marshal
,pickle
和json
模块; 在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+不再需要。
float
(双精度)和normal的round
,而不是numpy.double及其转换为字符串的问题。普通的Python舍入确实不能比Python 2.7更好。答案最多的是在2.7之前编写的,但是尽管它们本来就很好,但已过时了。这就是我回答的原因。
1
,“逐步下溢”期间除外。
a*b
VS b*a
。感谢您的链接-怀旧。
使用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文档中有关字符串格式的链接。
有关选项一的更多信息,此链接就足够了,并且具有有关各种标志的信息。
numvar=12.456
,则"{:.2f}".format(numvar)
产生12.46
但"{:2i}".format(numvar)
给出一个错误,并且我期望12
。
您可以使用格式运算符将值四舍五入到python中的小数点后2位:
print(format(14.4499923, '.2f')) // output is 14.45
在Python 2.7中:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
具有与完全相同的值a
,因此您最好也写print a
而不是print output
在最后一行。
13.95
。但是print a
,对于a
python 2.7中的特定值,也是如此,因此尚不清楚格式化步骤的重点。
a == output
过显示的代码?它给True
了我,我怀疑它也给你。
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
模块。
为了固定类型动态语言(例如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')
getcontext().prec = 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'
像这样的lambda函数呢?
arred = lambda x,n : x*(10**n)//1/(10**n)
这样,您可以执行以下操作:
arred(3.141591657,2)
并得到
3.14
就像1,2,3一样简单:
用十进制模块进行快速正确舍入的十进制浮点运算:
d =十进制(10000000.0000009)
实现四舍五入:
d.quantize(Decimal('0.01'))
将与 Decimal('10000000.00')
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)
PS:对他人的批评:格式不是四舍五入。
要将数字四舍五入为一种分辨率,最好的方法是使用以下方法,该方法可以在任何分辨率下工作(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
numpy.round
准确性/准确性。因此,在与分辨率相乘之前,需要将其定义为int。我更新了代码。谢谢你!
numpy.float64
np.round的结果转换为float
或简单地使用round(value, 2)
。在13.949999999999999(= 1395 / 100.)和3.950000000000001(= 1395 * .01)之间没有有效的IEEE 754号。您为什么认为自己的方法最好?原始值13.949999999999999289(= value = round(value,2))甚至比13.95000000000000178(np.float96打印)更精确。现在,我也将有关numpy的更多信息添加到我的答案中,您可能错误地投票了。本来不是numpy的。
int
也可以使用float
@szeitlin示例。感谢您的额外评论。(对不起,但我没有对您
我使用的方法是字符串切片。它相对简单快捷。
首先,将float转换为字符串,然后选择所需的长度。
float = str(float)[:5]
在上面的单行中,我们已将值转换为字符串,然后仅将字符串保留为其前四个数字或字符(包括首尾四个数字)。
希望有帮助!