Python浮点错误让我感到困惑

时间:2014-03-14 04:31:33

标签: python floating-point-precision

我刚刚遇到一个问题,我需要将数字附加到列表中,只要它们不在列表中,然后我必须通过比较来运行这些数字。问题出现在浮点算术错误中。为了说明我的代码中基本上发生了什么:

_list = [5.333333333333333, 6.666666666666667, ...]
number = some_calculation()
if number not in _list:
    _list.append(number) #note that I can't use a set to remove
                         #duplicates because order needs to be maintained
new_list = []
for num in _list:
    if some_comparison(num): #note that I can't combine 'some_comparison' with the
        new_list.append(num) #above check to see if the item is already in the list

问题是some_calculation()有时会生成一个不精确的数字,例如5.333333333333332,就我的计算需要而言,这与本例中_list中的第一个元素相同。我想到的解决方案是将生成的所有数字简化为小数点后9位左右。这工作了很短的时间,直到我意识到some_comparison再次将num与不精确的计算进行比较。即使我没有对_list中的数字进行舍入,some_comparison仍然会返回一个不精确的值,因此会评估为False。

我绝对感到困惑。我从来不必担心浮点错误,所以这个问题非常令人愤怒。有没有人对解决方案有任何想法?

注意:我会发布实际的代码,但它非常复杂,需要7或8个不同的函数和类我专门为此目的而制作,并将它们重新发布在这里会很麻烦。

3 个答案:

答案 0 :(得分:1)

进行比较

if(abs(a-b) <= 1e-6 * (a + b)):

这是使用浮点时的标准做法。您使用的实际值(而不是1e-6)取决于您使用的数字的大小以及您对#34;相同的&#34;的定义。

编辑我添加了*(a+b)为不同幅度的值提供了一些稳健性,并将比较更改为<=而非<以涵盖a==b==0.0

答案 1 :(得分:1)

您可以继承list并为__contains__添加容差:

class ListOFloats(list):
    def __contains__(self, f):
        # If you want a different tolerance, set it like so:
        # l=ListOFloats([seq])
        # l.tol=tolerance_you_want    
        tol=getattr(self, 'tol', 1e-12)
        return any(abs(e-f) <= 0.5 * tol * (e + f) for e in self) 

_list = ListOFloats([5.333333333333333, 6.666666666666667]) 

print(5.333333333333333 in _list)
# True
print(6.66666666666666 in _list)
# True
print(6.66666666666 in _list)
# False

答案 2 :(得分:0)

对列表中的值和比较值使用round。他们不会准确,但他们会保持一致,所以搜索会返回预期的结果。