I am aware of the nature of floating point math but I still find the following surprising:
from fractions import Fraction
print(Fraction(0.2)) # -> 3602879701896397/18014398509481984
print(Fraction(str(0.2))) # -> 1/5
print(Fraction(0.2)==Fraction(str(0.2))) # returns False
print(0.2 == float(str(0.2))) # but this returns True!
From the documentation I could not find anything that would explain that. It does state:
...In addition, any string that represents a finite value and is accepted by the float constructor is also accepted by the Fraction constructor...
but to me this implies a similar behavior to float()
which I just do not see as shown above.
Is there any explanation for this?
It is important to note that the behavior shown above is not specific to the value (0.2
) but rather general; everything I tried behaved the same way.
Interestingly enough:
from fractions import Fraction
for x in range(1, 257):
if Fraction(str(1/x))==Fraction(1/x):
print(x)
prints only the powers of 2 that are smaller than the selected upper bound:
1
2
4
8
16
32
64
128
256
3602879701896397/18014398509481984
is equal to 0.2... – Sequential3602879701896397/18014398509481985 = 0.2
– Dartboard0.2.as_integer_ratio()
, I think this is the relevant part from the docs, but it's rather brief: "Beware that Fraction.from_float(0.3) is not the same value as Fraction(3, 10)" docs.python.org/3.1/library/… – GodspeedFraction
class treatsfloat/Decimal
in a different way thenstr
argument. Have a look at souce code of it, specially this regex – Interferencefractions
module is more accurate with a string than with a float input. because floats are represented non-exactly in python, while strings need specific interpretation which can be made more accurate. – Dartboard