浮点除法的一致性

时间:2018-04-14 23:38:44

标签: python floating-point

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

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

在实践中,只需将a/bc/d进行比较即可,但是它是否有效? Python和/或IEEE-754中是否有某些东西可以保证这样的方案有效?

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

a = 1.0
b = 3.0
for c in xrange(1, 999):
    assert a / b == (a * c) / (b * c)

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

3 个答案:

答案 0 :(得分:4)

指定IEEE 754除法的行为就好像计算了除法的精确结果,然后舍入精确结果。如果a/bc/d在精确算术中具有相同的值,那么由于IEEE 754舍入是一致且确定的,因此a/bc/d必须在IEEE 754浮点中具有相同的结果点。

这仅适用于a/bc/d在精确算术中确实具有相同值的情况。 abcd中的舍入错误可能会导致此错误。而且,反过来并不成立;如果浮点数为a/b == c/d,则表示a/bc/d在精确算术中相等。

为什么不坚持整数,而不是处理浮点舍入?

a*d == b*c

可以在非整数算术中完成。或者,为什么不使用精确的理性类型?

from fractions import Fraction

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

答案 1 :(得分:2)

通过IEEE-754中的划分规定,如果 a / b = c / d ,那么a/b == c/d,前提是使用一种浮点格式按照IEEE-754中的规定评估a/b == c/d中的操作。 (Python没有做出这种保证;它继承了它所实现的任何平台的浮点行为,并且IEEE-754行为不是普遍保证的。)这是因为IEEE-754指定结果是精确的数学结果舍入到最近的可表示值(根据适用的舍入模式)。由于 a / b c / d 的数学结果相同,因此计算结果相同。< / p>

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

答案 2 :(得分:1)

好吧,我尝试了几个随机数,发现了这个。但正如@ 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)