我已经将其输入python shell:
>>> 0.1*0.1 0.010000000000000002
我期望0.1 * 0.1不是0.01,因为我知道以10为底的0.1是周期性的,以2为底。
>>> len(str(0.1*0.1)) 4
我已经看过20个以上的字符,因此我希望能得到20个。为什么我得到4?
>>> str(0.1*0.1) '0.01'
好吧,这解释了为什么我len给了我4,但为什么str回归'0.01'?
len
str
'0.01'
>>> repr(0.1*0.1) '0.010000000000000002'
为什么不str回合repr?(我已经阅读了这个答案,但是我想知道他们如何决定何时str对浮点数进行取整,以及何时对不进行浮点取整)
repr
>>> str(0.01) == str(0.0100000000001) False >>> str(0.01) == str(0.01000000000001) True
因此,浮子的准确性似乎是一个问题。我以为Python会使用IEEE 754单精度浮点数。所以我已经检查过了:
#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为什么会给我这些结果?
(我使用的是Python 2.6.5。如果您知道Python版本之间的差异,我也会对此感兴趣。)
关键的要求repr是它应该往返。也就是说,在所有情况下eval(repr(f)) == f都应给予True。
eval(repr(f)) == f
True
在Python 2.x(2.7之前的版本)中,它repr通过printf对format进行格式化%.17g并舍弃尾随零来工作。IEEE-754保证这是正确的(对于64位浮点数)。从2.7和3.1开始,Python使用了一种更智能的算法,该算法可以在某些情况下找到较短的表示形式,%.17g从而给出不必要的非零终端数字或终端数字9。请参阅3.1的新功能?并发行1580。
printf
%.17g
即使在Python 2.7下,也会repr(0.1 * 0.1)给出"0.010000000000000002"。这是因为0.1 * 0.1 == 0.01是False在IEEE-754解析和算法; 也就是说,与之最接近的64位浮点值与0.1自身相乘时,将得出一个64位的浮点值,该值不是与之最接近的64位浮点值0.01:
repr(0.1 * 0.1)
"0.010000000000000002"
0.1 * 0.1 == 0.01
False
0.1
0.01
>>> 0.1.hex() '0x1.999999999999ap-4' >>> (0.1 * 0.1).hex() '0x1.47ae147ae147cp-7' >>> 0.01.hex() '0x1.47ae147ae147bp-7' ^ 1 ulp difference
repr和之间str(2.7 / 3.1之前的版本)的区别在于,str格式具有12位小数而不是17位,这是不可四舍五入的,但是在许多情况下产生的可读性更高。