# fraction.py # Walker M. White (wmw2) # October 7, 2012 """Module with a simple Fraction class. This module shows off dispatch on type for add and multiply.""" import math def gcd(a,b): """Returns: Greatest common divisor of x and y. Precondition: x and y are integers.""" assert type(a) == int,`x`+' is not an int' assert type(b) == int,`y`+' is not an int' while b != 0: t = b b = a % b a = t return a class Fraction(object): """Instance is a fraction n/d""" # FIELDS _numerator = 0 # must be an int _denominator = 1 # must be an int > 0 # PROPERTIES @property # getter def numerator(self): """Fraction numerator. Invariant: Must be an int.""" return self._numerator # returns the field @numerator.setter # setter def numerator(self,value): # enforce invariant assert type(value) == int, `value`+' is not an int' # assign to field self._numerator = value @property # getter def denominator(self): """Fraction denominator. Invariant: Must be an int > 0.""" return self._denominator # returns the field @denominator.setter # setter def denominator(self,value): # enforce invariant assert type(value) == int, `value`+' is not an int' assert value > 0, `value`+' is not positive' # assign to field self._denominator = value # CONSTRUCTOR def __init__(self,n=0,d=1): """Constructor: Creates a new Fraction n/d Precondition: n an int, d > 0 an int.""" # No need for asserts; setters handle everything self.numerator = n self.denominator = d # OPERATORS def __str__(self): """Returns: this Fraction as a string 'n/d'""" return str(self.numerator)+'/'+str(self.denominator) def __repr__(self): """Returns: unambiguous representation of Fraction""" return str(self.__class__)+'['+str(self)+']' def __mul__(self,other): """Returns: Product of self and other as a new Fraction Does not modify contents of self or other Precondition: other is a Fraction or an int""" assert type(other) == Fraction or type(other) == int if type(other) == int: return self._multiplyInt(other) return self._multiplyFraction(other) # Private helper to multiply fractions def _multiplyFraction(self,other): # No need to enforce preconditions on a hidden method top = self.numerator*other.numerator bot = self.denominator*other.denominator return Fraction(top,bot) # Private helper to multiply ints def _multiplyInt(self,x): # No need to enforce preconditions on a hidden method top = self.numerator*x bot = self.denominator return Fraction(top,bot) def __rmul__(self,other): """Returns: Product of self and other as a new Fraction This method allows us to put the int on the left. Precondition: other is a Fraction""" assert type(other) == Fraction or type(other) == int if type(other) == int: return self._multiplyInt(other) return self._multiplyFraction(other) def __add__(self,other): """Returns: Sum of self and other as a new Fraction Does not modify contents of self or other Precondition: other is a Fraction""" assert type(other) == Fraction or type(other) == int if type(other) == int: return self._addInt(other) return self._addFraction(other) # Private helper to multiply fractions def _addFraction(self,other): # No need to enforce preconditions on a hidden method bot = self.denominator*other.denominator top = (self.numerator*other.denominator+ self.denominator*other.numerator) return Fraction(top,bot) # Private helper to multiply ints def _addInt(self,x): # No need to enforce preconditions on a hidden method bot = self.denominator top = (self.numerator+self.denominator*x) return Fraction(top,bot) def __radd__(self,other): """Returns: Sum of self and other as a new Fraction This method allows us to put the int on the left. Precondition: other is a Fraction""" assert type(other) == Fraction or type(other) == int if type(other) == int: return self._addInt(other) return self._addFraction(other) def __eq__(self,other): """Returns: True if self, other are equal Fractions. False if not equal, or other not a Fraction""" if type(other) != Fraction and type(other) != int: return False if type(other) == int: return self.numerator == other*self.denominator # Cross multiply left = self.numerator*other.denominator rght = self.denominator*other.numerator return left == rght def __ne__(self,other): """Returns: False if self, other are equal Fractions. True if not equal, or other not a Fraction""" return not self == other def __cmp__(self,other): """Returns: a negative integer if self < other, zero if self == other, a positive integer if self > other Used to implement comparison operations. Precondition: other is a Fraction.""" if type(other) != Fraction and type(other) != int: return False if type(other) == int: return self.numerator - other*self.denominator # Cross multiply left = self.numerator*other.denominator rght = self.denominator*other.numerator return left - rght # NORMAL METHODS def reduce(self): """Normalizes this fraction so that numerator and denominator have no common divisors.""" g = gcd(self.numerator,self.denominator) self.numerator = self.numerator/g self.denominator = self.denominator/g