## Fractions

If you have nightmares from trying to deal with fractions from your school days, Python’s Fraction data type may be just what you need. A Fraction is an object consisting of two integers, the numerator and denominator. To use it, you must import the fractions module. A basic Fraction can be constructed by passing it two integers as arguments. Try typing in the following into the console:

from fractions import *
Fraction(1, 3)
Fraction(5, 20)
Fraction(16, -64)
Fraction()
Fraction(13,0)
Fraction(1, 3)
Fraction(1, 4)
Fraction(-1, 4)
Fraction(0, 1)
ZeroDivisionError

The first line just returns a Fraction object equal to 1/3. The second line illustrates that Fraction automatically converts a fraction to its lowest terms: 5/20 = 1/4. The third line shows that a Fraction can be negative. The fourth line shows that the default values for the numerator and denominator are 0 and 1, respectively.

The final line shows that you can’t define a Fraction with a zero denominator, as you’d expect.

A Fraction can also be created from a float, although, as with Decimals, care is needed. If we naively write Fraction(33.24) for example, we get the result Fraction(4678114112931103, 140737488355328), which is probably not what you’d expect. However, if you divide 4678114112931103 by 140737488355328 you do, indeed, get 33.24. The problem, as usual with floats, is the roundoff error when trying to convert a float to binary form.

As with Decimals, we can get around this problem by passing a string version of a float to the Fraction constructor. If we try Fraction('33.24'), we get the result Fraction(831, 25). To figure out how Python arrived at this result, we look first at the fractional part of the argument, which is 0.24. In fractional form, this is 24/100, which reduces to 6/25. Thus the denominator will be 25. The numerator is calculated by converting the whole number part to 25ths and adding the 6: .

Another way of getting a sensible result for a Fraction from a float is to use the limit_denominator() function. Its argument specifies the largest integer that the denominator can be. With the example above, we can try

from fractions import *
Fraction(33.24).limit_denominator(2)
Fraction(33.24).limit_denominator(3)
Fraction(33.24).limit_denominator(25)
Fraction(33.24).limit_denominator(100)
Fraction(33, 1)
Fraction(100, 3)
Fraction(831, 25)
Fraction(831, 25)

Limiting the denominator to 2 produces the fraction 33/1 = 33, which is as good an approximation as we can get. Limiting the denominator to 3 gives us 100/3 = 33.333… Limiting the denominator to any integer from 25 up to 100 gives the exact answer of 831/25 = 33.24.

A Fraction can also be constructed from a Decimal. For example, we can write Fraction(Decimal('-97.5')) and get the result Fraction(-195, 2).

The numerator and denominator of a Fraction can be obtained by specifying the numerator or denominator property.

from fractions import *
x = Fraction(24, 37)
x.numerator
x.denominator

The third line returns 24 and the fourth line 37.

Fractions support the usual arithmetic operations, which makes them handy for adding up fractions with different denominators. For example, Fraction(1, 3) + Fraction(2, 5) produces Fraction(11, 15).

Functions from the math library can also be applied to Fractions, although in most cases the result will be a float, rather than another Fraction. For example:

from math import *
from fractions import *
x = Fraction(11, 15)
sqrt(x)
exp(x)
sin(x)