为什么str会舍入浮点数?

问题描述

| 传递带有许多小数的浮点数时,内置的Python str()函数输出一些奇怪的结果。这是发生了什么:
>>> str(19.9999999999999999)
>>> \'20.0\'
我期望得到:
>>> \'19.9999999999999999\'
有人知道为什么吗?也许解决方法? 谢谢!     

解决方法

不是四舍五入,而是您首先使用浮点数。浮点类型很快,但是精度有限;换句话说,它们在设计上是不精确的。这适用于所有编程语言。有关浮点怪的更多详细信息,请阅读“每个程序员应了解的浮点算术” 如果要存储精确数字并进行操作,请使用
decimal
模块:
>>> from decimal import Decimal
>>> str(Decimal(\'19.9999999999999999\'))
\'19.9999999999999999\'
    ,浮点数具有32位(至少在C中)。这些位之一分配给符号,一些分配给尾数,另外一些分配给指数。您不能将每个十进制数字都适合32位的无数位数。因此,浮点数很大程度上取决于舍入。 如果尝试
str(19.998)
,它可能会给您至少接近19.998的值,因为32位的精度足以估算该值,但是19.999999999999999之类的精度却无法以32位估算,因此四舍五入到最接近的可能值,这会发生变成20。     ,请注意,这是理解浮点(定长)数字的问题。大多数语言的功能完全(或非常类似于)Python。 Python“ 6”是IEEE 754 64位二进制浮点。它限制为53位精度,即略小于16位十进制数字。
19.9999999999999999
包含18个十进制数字;它不能完全表示为
float
float(\"19.9999999999999999\")
产生最接近的浮点值,恰好与
float(\"20.0\")
相同。
>>> float(\"19.9999999999999999\") == float(\"20.0\")
True
如果用“许多小数”表示“小数点后的许多数字”,请注意,当小数点前有许多小数位时,会出现相同的“怪异”结果:
>>> float(\"199999999999999999\")
2e+17
如果要获得完整的6精度,请不要使用str(),而应使用repr():
>>> x = 1. / 3.
>>> str(x)
\'0.333333333333\'
>>> str(x).count(\'3\')
12
>>> repr(x)
\'0.3333333333333333\'
>>> repr(x).count(\'3\')
16
>>>
更新有趣的是,经常将ѭ3处方为浮游症引起的惊讶的万灵药。这通常伴随着简单的示例,例如ѭ16。没有人停止指出“ 3”有其不足之处,例如。
>>> (1.0 / 3.0) * 3.0
1.0
>>> (Decimal(\'1.0\') / Decimal(\'3.0\'))  * Decimal(\'3.0\')
Decimal(\'0.9999999999999999999999999999\')
>>>
的确,
float
的精度限制为53个二进制数位。默认情况下,
decimal
限制为精度的28个十进制数字。
>>> Decimal(2) / Decimal(3)
Decimal(\'0.6666666666666666666666666667\')
>>>
您可以更改限制,但是它仍然是有限的精度。您仍然需要知道数字格式的特征才能有效地使用它,而不会产生“令人惊讶的”结果,并且通过较慢的操作获得了更高的精度(除非您使用第3方
cdecimal
模块)。     ,对于任何给定的二进制浮点数,都有无限的十进制小数集,在输入时会舍入到该数字。 Python的ѭ23有点麻烦,无法从该集合产生最短的十进制分数;有关一般算法,请参见GLS的论文http://kurtstephens.com/files/p372-steele.pdf(IIRC,他们在大多数情况下使用避免任意精度数学的改进方法)。您碰巧输入了一个小数部分,该小数部分四舍五入为一个浮点数(IEEE整数),其最短的十进制小数部分与您输入的小数部分不同。