# betterfraction.py # Walker M. White (wmw2) # October 7, 2012 """Module with a simple Fraction class. This module shows off operator overloading. This allows us to define complex mathematical objects. This version of Fraction uses get and set methods. This allows us to enforce our invariants, but is very unwieldy. Notice the use of get and set methods EVERYWHERE.""" 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 a fraction n/d""" # HIDDEN FIELDS _numerator = 0 # must be an int _denominator = 1 # must be an int > 0 # GET AND SET METHOD def getNumerator(self): """Returns: Fraction numerator.""" return self._numerator # returns the field def setNumerator(self,value): """Sets the numerator to value. Precondition: value is an int""" # enforce invariant assert type(value) == int, `value`+' is not an int' # assign to field self._numerator = value def getDenominator(self): """Fraction denominator. Invariant: Must be an int > 0.""" return self._denominator # returns the field def setDenominator(self,value): """Sets the numerator to value. Precondition: value is an int > 0""" # 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.setNumerator(n) self.setDenominator(d) def __init__(self,n=0,d=1): """Constructor: Creates a new Fraction n/d Precondition: n an int, d > 0 an int.""" assert type(n) == int,`n`+' is not an int' assert type(d) == int,`d`+' is not an int' assert d > 0,`d`+' is not positive' self.setNumerator(n) self.setDenominator(d) def __str__(self): """Returns: this Fraction as a string 'n/d'""" return str(self.getNumerator())+'/'+str(self.getDenominator()) 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""" assert type(other) == Fraction top = self.getNumerator()*other.getNumerator() bot = self.getDenominator()*other.getDenominator() return Fraction(top,bot) 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 bot = self.getDenominator()*other.getDenominator() top = (self.getNumerator()*other.getDenominator()+ self.getDenominator()*other.getNumerator()) return Fraction(top,bot) 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: return False # Cross multiply top = self.getNumerator()*other.getNumerator() bot = self.getDenominator()*other.getDenominator() 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.""" assert type(other) == Fraction # Cross multiply top = self.getNumerator()*other.getNumerator() bot = self.getDenominator()*other.getDenominator() return left - rght def reduce(self): """Normalizes this fraction so that numerator and denominator have no common divisors.""" g = gcd(self.getNumerator(),self.getDenominator()) self.setNumerator(self.getNumerator()/g) self.setDenominator(self.getDenominator()/g)