浮点比较(1.0 == 1.0)总是为假

-2 投票
5 回答
2380 浏览
提问于 2025-04-18 16:08

我在使用Python 2.7.3和Kivy 1.8.0时,想让一个网格(Grid)小部件渐变显示,所以用了下面这个函数:

def __init__(self, **kwargs):
     # ...Init parent class here...
     self.grid.opacity = 0.0
     Clock.schedule_interval(self.show, 1 / 10)

def show(self, value):
    if self.grid.opacity == 1.0:
        return False
    else:
        self.grid.opacity += 0.1

show()这个函数一直在执行,self.grid.opacity == 1.0总是返回False,所以调度器(scheduler)就一直没有把这个函数移除。

我本以为,文档上说opacity是一个NumericProperty,默认值是1.0,但是我在调用show()之前已经改变了它的值。

这是我尝试过的:

if self.grid.opacity == NumericProperty(1.0):

if float(self.grid.opacity) == 1.0:

但是这个方法不管用。而且,我确认self.grid.opacity确实是1.0,在我进行比较之前,type()也返回了float

这个方法可以用:

if str(self.grid.opacity) == "1.0":

但显然我不喜欢这个解决方案。

有没有什么好的主意?

5 个回答

1

@Basile Starynkevitch 解释了为什么会出现这种情况,这和浮点数的特性有关。进行这种比较的一般形式是:

abs(numberA - numberB) <= SOMEEPSILON

这里的 SOMEEPSILON 是你认为可以接受的误差范围。

如果你处理的是较小的数字,并且不担心四舍五入的误差,可以使用 sys.float_info.epsilon

所以,正如我评论的,结合这两者你可以得到:

abs(self.grid.opacity - 1.0) <= sys.float_info.epsilon

文档中对 epsilon 值的定义是:

1 和大于 1 的最小可表示浮点数之间的差值

换句话说,就是 1 和它前面那个数之间的最小值。

举个例子,如果 Python 只能表示到小数点后两位,epsilon 就是 1.00 和 0.99 之间的差值(实际上这个值要小得多)。

3

这是你的问题:

>>> q=0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1
>>> str(q)
'1.0'
>>> q
0.9999999999999999
>>> q==1
False

简单来说,永远不要用 == 来比较浮点数。

4

这可能是浮点数比较的问题。我不知道具体的应用场景,但浮点数从来都不是精确的,所以用它们来判断是否相等可能会出问题。你可以试试下面这种方法:

if abs(float(self.grid.opacity) - 1.0) < .001:
    pass

这是一个有趣的浮点数表现的例子,至少在我的环境下是这样的:

>>> .1 + .1 + .1 == .3
False
>>> .1 + .1 == .2
True
4

这可能不是Python特有的问题。可以看看每个程序员都应该知道的浮点数运算

0.1这个数字在计算机里并不能被完全准确地表示成一个IEEE754双精度浮点数。所以我猜从0.1解析出来的浮点数(其实它并不是完全等于十分之一)在转换成字符串“0.1”时可能会出现问题。

2

正如其他人所说,这个问题是因为浮点数的存储方式造成的。虽然你可以尝试一些变通的方法,但其实有更好的解决办法:Animation

__init__ 里面:

self.grid.opacity = 0
anim = Animation(opacity=1)
anim.start(self.grid)

撰写回答