Python 浮点除法的一致性

Python 浮点除法的一致性,python,floating-point,Python,Floating Point,众所周知,浮点值不能精确地表示每个十进制值。因此,1/3的浮点值并不完全是1/3。因此,直接比较浮点值通常是不可取的 然而,在这个应用程序中,我试图确定两个分数a/b和c/d是否相等。如果是,则存在整数e和f,使得a*e=c*f和b*e=d*f。假设a、b、c、d、e、f都是正整数,可以用浮点值精确表示 在实践中,简单地将a/b与c/d进行比较是可行的,但它能保证有效吗?Python和/或IEEE-754中是否有某种东西可以保证这样的方案工作? 示例代码(显示此方案适用于合理数量的值): 如果不

众所周知,浮点值不能精确地表示每个十进制值。因此,1/3的浮点值并不完全是1/3。因此,直接比较浮点值通常是不可取的

然而,在这个应用程序中,我试图确定两个分数a/b和c/d是否相等。如果是,则存在整数e和f,使得
a*e=c*f
b*e=d*f
。假设a、b、c、d、e、f都是正整数,可以用浮点值精确表示

在实践中,简单地将
a/b
c/d
进行比较是可行的,但它能保证有效吗?Python和/或IEEE-754中是否有某种东西可以保证这样的方案工作?

示例代码(显示此方案适用于合理数量的值):


如果不能保证这一点,是否存在一个反例,其值为a、b、c、d,使得a/b=c/d(在数学中),但Python无法比较
a/b==c/d
?同样,这些都是正整数,Python可以在其浮点值中精确表示。

好吧,我尝试了一些随机数,发现了这一点。但正如@user2357112所指出的,这更多地是由于测试的缺陷,而不是一个好的例子

把这个放在这里是为了证明事实

a = 653543435456556.0
b = 3.0

for c in range(1, 999):
    assert a / b == (a * c) / (b * c), (c, a / b - (a * c) / (b * c))

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-128-405615b37738> in <module>()
      2 b = 3.0
      3 for c in range(1, 999):
----> 4     assert a / b == (a * c) / (b * c), (c, a / b - (a * c) / (b * c))
      5 

AssertionError: (57, -0.03125)
a=65354354556.0
b=3.0
对于范围(1999)内的c:
断言a/b==(a*c)/(b*c),(c,a/b-(a*c)/(b*c))
---------------------------------------------------------------------------
AssertionError回溯(上次最近的调用)
在()
2b=3.0
3表示范围(1999)内的c:
---->4断言a/b==(a*c)/(b*c),(c,a/b-(a*c)/(b*c))
5.
断言错误:(57,-0.03125)

IEEE 754除法的行为指定为计算除法的精确结果,然后对精确结果进行四舍五入。如果
a/b
c/d
在精确算法中具有相同的值,那么由于IEEE 754舍入是一致和确定的,
a/b
c/d
在IEEE 754浮点运算中必须具有相同的结果

但是,只有当
a/b
c/d
在精确算法中确实具有相同的值时,这一点才成立。
a
b
c
d
中的舍入错误会导致此问题。同样,反之亦然;如果浮点形式的
a/b==c/d
,这并不意味着
a/b
c/d
在精确算术上相等


与其处理浮点舍入,为什么不坚持整数呢

a*d == b*c
可以在未舍入整数算术中完成。或者,为什么不使用精确的rational类型呢

from fractions import Fraction

Fraction(a, b) == Fraction(c, d)

根据IEEE-754中的除法规范,如果a/b=c/d,则
a/b==c/d
,前提是
a/b==c/d
中的操作按照IEEE-754中的规定使用一种浮点格式进行评估。(Python不保证这一点;它继承了它在任何平台上实现的浮点行为,并且IEEE-754的行为没有得到普遍保证。)这是因为IEEE-754指定结果是精确的数学结果,四舍五入到最接近的可表示值(根据适用的四舍五入模式)。由于a/b和c/d的数学结果相同,因此计算结果相同


然而,
a/b==c/d
并不意味着a/b=c/d。一个反例是
1/(0x1p53-1)
1/(0x1p53-2)
都产生1.1102230246251567869426645496570095036651766508706967728770109715696889907216583251953125•10−16(十六进制浮点,0x1.0000000000001p-53)。

这不是唯一类型的计数器示例;你也可以认为a/b不等于c/d,但
a/b==c/d
。你的问题里面已经回答了你自己的问题。@Scott Hunter,说得好,误报也很有意思。然而,假阴性更令人感兴趣。这就是您要解决的问题:给定浮点值a、b、c和d,确定a/b在数学上是否等于c/d,而不受浮点运算的影响?但由于
a*c
中的舍入错误,这会失败。在舍入误差之后,分数在精确算术中的结果就不一样了。这与其说是划分不一致,不如说是提问者测试中的一个缺陷。
from fractions import Fraction

Fraction(a, b) == Fraction(c, d)