Reputation: 2169
It is well known that floating point values cannot exactly represent every decimal value. Thus, the floating point value for 1/3 is not exactly 1/3. For this reason, it is generally inadvisable to compare floating point values directly.
However, in this application, I am trying to determine if two fractions a / b and c / d are equivalent. If they are, then there exist integers e and f such that a * e = c * f
and b * e = d * f
. Assume a, b, c, d, e, f are all positive integers which can be represented exactly in a floating point value.
In practice, simply comparing a/b
to c/d
worked, but is it guaranteed to work? Is there something within Python and/or IEEE-754 that would guarantee such a scheme to work?
Example code (that shows this scheme works for a reasonable number of values):
a = 1.0
b = 3.0
for c in xrange(1, 999):
assert a / b == (a * c) / (b * c)
If this is not guaranteed, is there a counterexample with values a, b, c, d such that a/b = c/d (in math) but Python fails to compare a / b == c / d
? Again, these are all positive integers which Python can exactly represent in its floating point value.
Upvotes: 3
Views: 528
Reputation: 222273
By specification of division in IEEE-754, if a/b = c/d, then a/b == c/d
, provided that the operations in a/b == c/d
are evaluated as specified in IEEE-754 using one floating-point format. (Python does not make this guarantee; it inherits the floating-point behavior of whatever platform it is implemented on, and IEEE-754 behavior is not universally guaranteed.) This is because IEEE-754 specifies that the result is the exact mathematical result rounded to the nearest representable value (according to the applicable rounding mode). Since the mathematical results are identical for a/b and c/d, the computed results are identical.
However, a/b == c/d
does not imply a/b = c/d. A counterexample is that 1 / (0x1p53-1)
and 1 / (0x1p53-2)
both produce 1.11022302462515678694266454965700950366517665087069677287701097156968899071216583251953125 • 10−16 (in hexadecimal floating-point, 0x1.0000000000001p-53).
Upvotes: 2
Reputation: 280182
IEEE 754 division is specified to behave as if you computed the exact result of the division and then rounded the exact result. If a/b
and c/d
have the same value in exact arithmetic, then since IEEE 754 rounding is consistent and deterministic, a/b
and c/d
must have the same result in IEEE 754 floating point.
This only holds if a/b
and c/d
really do have the same value in exact arithmetic, though. Rounding error in a
, b
, c
, or d
can throw this off. Also, the converse doesn't hold; if a/b == c/d
in floating point, that doesn't mean a/b
and c/d
are equal in exact arithmetic.
Rather than dealing with floating-point rounding, why not stick to integers?
a*d == b*c
can be done in unrounded integer arithmetic. Alternatively, why not use an exact rational type?
from fractions import Fraction
Fraction(a, b) == Fraction(c, d)
Upvotes: 5
Reputation: 164613
Well, I tried a few random numbers and found this. But as @user2357112 points out, this more due to a deficiency of the test than a good example.
Leaving this here to demonstrate the fact.
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)
Upvotes: 1