奇怪的行为:附加到列表

时间:2015-06-22 06:32:45

标签: python python-2.7 behavior

我正在编写一个简单的函数来逐步调整具有浮动步长的范围。为了保持输出的整洁,我编写了一个函数correct,它可以纠正算术运算后常见的浮点错误。

也就是说:correct(0.3999999999)输出0.4correct(0.1000000001)输出0.1等。

这是代码的主体:

floats = []  
start = 0  
end = 1  
stepsize = 0.1  
while start < end:
    floats.append(start)
    start = correct(start + stepsize)

最后,输出看起来好像没有得到纠正:
[0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]

为了检查这一点,我插入了一个print语句来查看附加内容:

floats = []  
start = 0  
end = 1  
stepsize = 0.1  
while start < end:
    print start
    floats.append(start)
    start = correct(start + stepsize)

这些印刷语句的输出是:

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0

所以我知道correct功能正常运行。因此,似乎当start附加到floats时,分配中会发生某些事情,导致浮点错误再次爆发。

事情变得更糟。我将变量z分配给输出,即z = [0,0.1,...]。我尝试print z,按预期打印看起来没有修正的输出:

[0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]

现在我尝试for a in z: print a。打印出来:

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0

但是这与print z中的输出不对应:其中一个有浮点错误,另一个没有。

最后,我尝试print [correct(x) for x in z]。我再次得到未经修正的输出。

我希望我已经清楚地表明了我遇到的困惑。为什么打印列表看起来与单独打印每个项目有什么不同?为什么列表中的变量不受correct函数的影响?我希望这是由于列表中浮点数的一些内部存储器表示?

最后,我如何确保输出只是[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

我正在使用Python 2.7.9。

4 个答案:

答案 0 :(得分:3)

简短回答:您的correct无效。

答案很长:
在现代计算机和编程语言中普遍使用的二进制浮点格式不能代表大多数数字,如0.1,就像没有终止十进制表示可以代表1/3一样。相反,当您在源代码中写入0.1时,Python会自动将其转换为3602879701896397/2 ^ 55,a.k.a。0.1000000000000000055511151231257827021181583404541015625,可以用二进制表示。然后,Python面临一个如何在打印时显示0.1000000000000000055511151231257827021181583404541015625的问题。

Python有两种方法可以生成事物的字符串表示:strrepr。在Python 2中,strrepr的实现为如何显示浮点数做出了不同的选择。两者都不能产生精确的表示。相反,str将字符串截断为12位,这隐藏了一些舍入错误,代价是显示一些非常接近的浮点数,而repr截断为17位,足以使不同的浮点数总是以不同的方式显示。

当您print浮动时,Python使用str。这意味着您的print start语句使其看起来像correct。但是,当您print列表时,列表的str实现会在其内容上使用repr(出于好的原因,我不会在此处讨论),因此print列表显示您的correct实际上没有产生您想要的数字;如果您的correct生成了Python源代码中0.3生成的数字,那么Python会将其显示为0.3

答案 1 :(得分:1)

使用round()代替正确生成你想要的东西:

    start = round(start + stepsize, 1)

round()是一个内置函数:

round(...)
    round(number[, ndigits]) -> floating point number

    Round a number to a given precision in decimal digits (default 0 digits).
    This always returns a floating point number.  Precision may be negative.

所以我猜可能正确的功能

有问题

答案 2 :(得分:1)

我想这里发生的事情是print正常工作并显示舍入值而你的功能没有。

解释非常简单:虽然可以将float转换为具有正确(舍入)值的字符串,但是不能在float中存储一些浮点值。因此,您的correct()无法更正该值并返回浮点数,它将遇到同样的问题。

答案 3 :(得分:0)

它应该是常见问题解答,但我找不到与您的问题相关的答案。

Python(几乎所有语言都使用IEE764来表示浮点化元素。这意味着我们干净整洁的小数(0.3,0.2,0.1)没有精确表示为浮点数。只有数字组成的负数为2可以:0.5,0.25,0.75有精确的表示。所以当你尝试对它进行舍入或截断时,处理器会做得最好,并且会返回最接近你要求的数字并且它可以代表(单个约7位小数)精确数字和13为双)