# bestfraction.py # Walker M. White (wmw2) # October 7, 2015 """Module with a simple Fraction class. This module shows off operator overloading. This allows us to define complex mathematical objects. This version of Fraction has properties, which allow us to enforce our invariants. This is the prefered way to make a class in Python""" 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 INSTANCE ATTRIBUTES: _numerator: [int] _denominator: [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): # DO NOT WRITE A SEPARATE SPECIFICATION FOR SETTER # 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 # INITIALIZER def __init__(self,n=0,d=1): """Initializer: Creates a new Fraction n/d Parameter n: the numerator (default is 0) Precondition: n is an int (or optional) Parameter d: the denomenator (default is 1) Precondition: d is an int (or optional) """ # 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: The unambiguous representation of Fraction""" return str(self.__class__)+'['+str(self)+']' def __mul__(self,other): """Returns: Product of self and other as a new Fraction This method does not modify the contents of self or other Parameter other: the fraction to multiply on the right Precondition: other is a Fraction""" assert type(other) == Fraction top = self.numerator*other.numerator bot = self.denominator*other.denominator return Fraction(top,bot) def __add__(self,other): """Returns: Sum of self and other as a new Fraction This method does not modify the contents of self or other Parameter other: the fraction to add on the right Precondition: other is a Fraction""" assert type(other) == Fraction bot = self.denominator*other.denominator top = (self.numerator*other.denominator+ self.denominator*other.numerator) return Fraction(top,bot) def __eq__(self,other): """Returns: True if self, other are equal Fractions. It returns False if they are not equal, or other is not a Fraction Parameter other: value to compare to this fraction Precondition: NONE""" if type(other) != Fraction: return False # 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. It returns True if they are not equal, or other is not a Fraction Parameter other: value to compare to this fraction Precondition: NONE""" return not self == other def __cmp__(self,other): """Returns: whether self < other, self == other, or self > other This method returns an integer. The value is negative is self < other. The value is zero if self == other. Finally, the value is positive if self > other. The actual value returned does not matter and is not specified. This method is used to implement all comparison operations. Parameter other: value to compare to this fraction Precondition: other is a Fraction""" assert type(other) == Fraction # Cross multiply left = self.numerator*other.denominator rght = self.denominator*other.numerator return left - rght # NORMAL METHODS def reduce(self): """Normalizes this fraction into simplest form. Normalization ensures that the numerator and denominator have no common divisors.""" g = gcd(self.numerator,self.denominator) self.numerator = self.numerator/g self.denominator = self.denominator/g