1

I'm writing a program that uses the Fractions module. I want to get the most simplified fraction of a float. When I try it with numbers like 0.5, it works correctly:

>>> import fractions
>>> str(fractions.Fraction(0.5))
'1/2'

But when I try it with 0.55 or 0.1 it displays fractions with very high numerator and denominator, instead of 11/20 and 1/10.

>>> str(fractions.Fraction(0.1))
'3602879701896397/36028797018963968'
>>> str(fractions.Fraction(0.55))
'2476979795053773/4503599627370496'

What can I do to be sure that the script will always display the most simplified fraction? Is there any way to do it with Fractions module or another module, or I have to write the function myself?

Mehrdad Pedramfar
  • 10,941
  • 4
  • 38
  • 59
ARD
  • 333
  • 1
  • 13
  • When you pass `0.55` you are passing in a float, so it is already an inexact representation before the `Fraction` receives the value – khelwood Feb 03 '19 at 12:32
  • The crux is that simple decimal fractions like e.g. 0.1 are often periodic fractions in the dual system. The floating point numbers used in the computer make it even more worse. Recommended reading: [Floating point guide](http://floating-point-gui.de/). – Scheff's Cat Feb 03 '19 at 12:33
  • If you pass a string like `Fraction('0.1')` it will work. – Alex Hall Feb 03 '19 at 12:34
  • @khelwood Do you know what causes the giant numbers to appear for `0.1`? Is there some deterministic rule for this? – roganjosh Feb 03 '19 at 12:34
  • @roganjosh Only that the float will try and store the closest value to 0.1 that fits its binary representation. – khelwood Feb 03 '19 at 12:36
  • Ok, so I'll pass the number as a string. This solves the problem – ARD Feb 03 '19 at 12:42
  • 1
    It's not dulicate of https://stackoverflow.com/questions/23344185/how-to-convert-a-decimal-number-into-fraction. It doesn't explain why I have to pass the number as a string. – ARD Feb 03 '19 at 12:45

4 Answers4

3

When you pass 0.55 you are passing in a float, so it is already an inexact representation before the Fraction receives the value.

Alternatively, if you pass a string instead, you can get the exact value you want:

>>> fractions.Fraction('0.55')
Fraction(11, 20)
khelwood
  • 55,782
  • 14
  • 81
  • 108
2

Try this:

fractions.Fraction(0.1).limit_denominator()

See the results:

In [77]: str(fractions.Fraction(0.55).limit_denominator())
Out[77]: '11/20'

In [78]: str(fractions.Fraction(0.1).limit_denominator())
Out[78]: '1/10'
Mehrdad Pedramfar
  • 10,941
  • 4
  • 38
  • 59
0

Try with decimal module example from the docs:

>>> from fractions import Fraction
>>> from decimal import Decimal
>>> Fraction(Decimal('0.55'))
>>> Fraction(11, 20)
>>> str(Fraction(11, 20))
>>> '11/20'
funnydman
  • 9,083
  • 4
  • 40
  • 55
0

Pass it as string to get the simplified fraction:

>>> fractions.Fraction('0.1')
Fraction(1, 10)
>>> str(fractions.Fraction('0.1'))
'1/10'
Austin
  • 25,759
  • 4
  • 25
  • 48