I decided to train myself in OOP with a simple perfect precision Fraction class.
from __future__ import division
import doctest
class Fraction:
"""
Implements a Fraction Class with perfect precision
operations and utility methods. The built-in operators
are overwritten to provide a more natural interface.
"""
def __init__(self,num,den):
if den == 0:
raise ValueError("Denominator must not be zero.")
self.num = num
self.den = den
@staticmethod
def greatest_common_divisor(a,b):
"""
Returns the greatest number 'n' existing such
that a % n == 0 and b % n == 0.
This number may be one if 'a' and 'b' are coprimes.
>>> Fraction.greatest_common_divisor(20,15)
5
"""
def common(a,b):
return [i for i in a if i in b]
def div(n):
return [i for i in range(1,n+1) if n % i == 0]
return max(common(div(a),div(b)))
@staticmethod
def invert(fraction):
"""
Returns a fraction where the numerator is the previous
denominator and vice-versa.
>>> Fraction.invert(Fraction(3,5))
5/3
"""
return Fraction(fraction.den,fraction.num)
def from_string(text):
"""
Generates a Fraction object from a string rapresentation
of two integers seperated by '/'.
>>> Fraction.from_string('4/9') + Fraction.from_string('2/18')
5/9
"""
return Fraction(*[int(i) for i in text.split('/')])
def simplify(self):
"""
Returns an eqivalent but simpler Fraction.
>>> Fraction.simplify(Fraction(210,20))
21/2
"""
fact = self.greatest_common_divisor(self.num,
self.den)
return Fraction(self.num // fact, self.den // fact)
def __mul__(self,fraction):
"""
Fraction multiplication.
>>> Fraction(4,3) * Fraction(1,20)
1/15
"""
return Fraction.simplify(
Fraction(self.num*fraction.num,
self.den*fraction.den))
def __add__(self,fraction):
"""
Fraction addition.
>>> Fraction(4,9) + Fraction(11,7)
127/63
"""
common_den = self.greatest_common_divisor(
self.den,fraction.den)
num1 = self.num * fraction.den
num2 = fraction.num * self.den
return Fraction.simplify(
Fraction(num1+num2, fraction.den*self.den))
def __sub__(self,fraction):
"""
Fraction subtraction.
>>> Fraction(1,2) - Fraction(1,3)
1/6
"""
return self + Fraction(-fraction.num,
fraction.den)
def __truediv__(self,fraction):
"""
Fraction division.
>>> Fraction(4,8) / Fraction(9,2)
1/9
"""
return self * self.invert(fraction)
def __repr__(self):
"""
Returns a printable representation of the fraction
that can also be fed back into the class via
'Fraction.from_string'.
This method is called automatically on printing.
>>> Fraction(5,8)
5/8
>>> Fraction(2,9)
2/9
"""
return '{}/{}'.format(self.num, self.den)
def main():
doctest.testmod()
if __name__ == "__main__":
main()