I need to write a python function that takes, as an argument, an object of class "Fraction", and determines whether the fraction can be represented in decimal format. For example, 1/2 can be represented by 0.5, but 1/3 has no decimal equivalent with finite number of digits (0.333333333 is an approximated value).
My approach was to compare the fraction with the numerator divided by the denominator as follows (assume that "frac" is the Fraction object):
if frac == frac.numerator / frac.denominator:
print('has decimal representaion')
else:
print('has no decimal representation')
but this doesn't work in many cases. For example Python mistakes the comparison Fraction(347, 1000) == 0.347
, it returns False
although it should be True
.
I know that python has a problem related to floating point operations, therefor I am looking for a workaround or a package that solves this problem.
Note: I used sympy but in sympy the comparison S(1)/3 == 1/3
returns True
, where I need it to be False
.
Using this:
If the denominator is has any prime factors other than 2 and 5, it doesn't have an exact decimal representation. – khelwood
You could test this by dividing out the 2s and then 5s and then checking if the result is 1:
def has_decimal_representaion(frac):
d = frac.denominator
for n in (2, 5):
while d % n == 0:
d = d / n
return d == 1
The problem with checking Fraction(1, 3) == float(1/3)
is that float(1/3)
is also technically a rational number, since it's a finitely represented floating point number. To be sure that rational number is 6004799503160661/18014398509481984
:
>>> (1/3).as_integer_ratio()
(6004799503160661, 18014398509481984)
This method would only work if computers could store infinitely many digits for a floating point number, which is impossible.
As for the easier test suggested by khelwood, if the denominator has factors other than 2 or 5, you can use SymPy's factorint
with the limit
argument to prevent it from trying to find large prime factors. Note that fraction.Fraction
and sympy.Rational
objects are always reduced to lowest terms automatically, so you don't need to worry about that.
def is_representable(rational):
d = sympy.Rational(rational).q
return not bool(set(sympy.factorint(d, limit=10).keys()) - {2, 5})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With