我在python shell中输入了以下内容:
>>> 0.1*0.1
0.010000000000000002
我预期0.1*0.1不是0.01,因为我知道0.1在基数10中是周期性的,在基数2中是周期性的。在
^{pr2}$我期望得到20个,因为我看到了上面的20个字符。为什么我得4分?在
>>> str(0.1*0.1)
'0.01'
好的,这解释了为什么我len
给了我4,但是{
>>> repr(0.1*0.1)
'0.010000000000000002'
为什么str
不圆而{str
取整浮点数和不取整浮点数的)
>>> str(0.01) == str(0.0100000000001)
False
>>> str(0.01) == str(0.01000000000001)
True
所以这似乎是一个浮动精度的问题。我以为Python会使用ieee754单精度浮点。所以我检查了一下:
#include <stdint.h>
#include <stdio.h> // printf
union myUnion {
uint32_t i; // unsigned integer 32-bit type (on every machine)
float f; // a type you want to play with
};
int main() {
union myUnion testVar;
testVar.f = 0.01000000000001f;
printf("%f\n", testVar.f);
testVar.f = 0.01000000000000002f;
printf("%f\n", testVar.f);
testVar.f = 0.01f*0.01f;
printf("%f\n", testVar.f);
}
我得到了:
0.010000
0.010000
0.000100
Python给了我:
>>> 0.01000000000001
0.010000000000009999
>>> 0.01000000000000002
0.010000000000000019
>>> 0.01*0.01
0.0001
为什么Python会给出这些结果?在
(我使用python2.6.5。如果您知道Python版本之间的差异,我也会对它们感兴趣。)
from python tutorial:
关于}。在
repr
的关键要求是它应该往返;也就是说,eval(repr(f)) == f
在所有情况下都应该给出{在python2.x(2.7之前的版本)中,
repr
的工作方式是使用%.17g
格式执行printf
,并丢弃尾随的零。IEEE-754保证这是正确的(对于64位浮点)。从2.7和3.1开始,Python使用了一种更智能的算法,在某些情况下,%.17g
给出了不必要的非零终端数字或终端9,这种算法可以找到更短的表示。请参见What's new in 3.1?和issue 1580。在即使在Python2.7中,
repr(0.1 * 0.1)
也给出了"0.010000000000000002"
。这是因为根据IEEE-754解析和算术,0.1 * 0.1 == 0.01
是False
;也就是说,与0.1
最近的64位浮点值相乘时,将生成一个64位浮点值,该值不是最接近0.01
的64位浮点值:repr
和{我可以证实你的行为
现在,Python<;2.7中的文档claim
这只是一个小小的简化。在
<>请注意,这与字符串
另外,即使你知道有更好的浮点数,也有点不舒服。实际上,在现代Pythons中,一种新的算法被用于浮点格式,它以一种聪明的方式选择最短的表示。在
我花了一段时间在源代码中查找,所以我将在这里包括详细信息,以防您感兴趣。你可以跳过这一节。在
在
^{pr2}$floatobject.c
中,我们看到这让我们来看看
format_float
。省略NaN/inf特殊情况,它是:我们可以看到
因此,这首先初始化一些变量并检查
v
是否是格式良好的浮点。然后准备一个格式字符串:现在PREC_REPR在
floatobject.c
的其他地方定义为17,因此这将计算到"%.17g"
。现在我们打电话来看到隧道的结尾后,我们查找^{} ,发现它在内部使用
snprintf
。在相关问题 更多 >
编程相关推荐