# -*- coding: utf-8 -*-
"""CMPSC132 - Homework 1.ipynb
I have included that code snippets for the PSADS book below. You need to extend the code in order to meet the criteria listed at the end of the chapter.
"""
def gcd(m, n):
while m % n != 0:
m, n = n, m % n
return n
def chk_frac(frac):
try:
onum = frac.num
oden = frac.den
except AttributeError:
onum = frac
oden = 1
return onum, oden
class Fraction:
def __init__(self, top, bottom):
if (type(top) is not int) or (type(bottom) is not int):
raise TypeError
if bottom < 0:
bottom *= -1
top *= -1
cmmn = gcd(top, bottom)
self.num = top // cmmn
self.den = bottom // cmmn
def __str__(self):
return "{:d}/{:d}".format(self.num, self.den)
def __eq__(self, other_fraction):
first_num = self.num * other_fraction.den
second_num = other_fraction.num * self.den
return first_num == second_num
def __add__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
new_num = self.num * oden \
+ self.den * onum
new_den = self.den * oden
return Fraction(new_num, new_den)
def __sub__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
new_num = self.num * oden \
- self.den * onum
new_den = self.den * oden
return Fraction(new_num, new_den)
def __mul__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
new_num = self.num * onum
new_den = self.den * oden
return Fraction(new_num, new_den)
def __truediv__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
new_num = self.num * oden
new_den = self.den * onum
return Fraction(new_num, new_den)
def __gt__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
snum = self.num * oden
onum = self.den * onum
if snum > onum:
return True
return False
def __ge__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
snum = self.num * oden
onum = self.den * onum
if snum >= onum:
return True
return False
def __lt__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
snum = self.num * oden
onum = self.den * onum
if snum < onum:
return True
return False
def __le__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
snum = self.num * oden
onum = self.den * onum
if snum <= onum:
return True
return False
def __ne__(self, other_fraction):
onum, oden = chk_frac(other_fraction)
snum = self.num * oden
onum = self.den * onum
if snum != onum:
return True
return False
def __radd__(self, other_fraction):
"""
__radd__ is for when the reverse adding is needed
like 1 + x instead of x + 1
"""
return self.__add__(other_fraction)
def __iadd__(self, ofrac):
"""
__iadd__ is for increment addition
x += 5
"""
onum, oden = chk_frac(ofrac)
self.num = self.num * oden + onum * self.den
self.den = self.den * oden
return self
def __repr__(self):
"""
__repr__ is similar to __str__ because it returns a string that
displays the state of the object but __repr__ can be used to
recreate the object while __str__ prints the state in a human
readable format.
"""
return f"Fraction({self.num}, {self.den})"
def show(self):
print("{:d}/{:d}".format(self.num, self.den))
def get_num(self):
return self.num
def get_den(self):
return self.den
x = Fraction(1, 2)
x.show()
y = Fraction(2, 3)
print(y)
assert y == Fraction(2,3)
print(x + y)
assert x + y == Fraction(7,6)
print(x == y)
"""# COMPLETE THE FRACTION CLASS
You can also find these questions in the book.
1. Implement the simple methods get\_num and get\_den that will return the numerator and denominator of a fraction.
2. In many ways it would be better if all fractions were maintained in lowest terms right from the start. Modify the constructor for the Fraction class so that GCD is used to reduce fractions immediately. Notice that this means the \_\_add\_\_ function no longer needs to reduce. Make the necessary modifications.
3. Implement the remaining simple arithmetic operators (\_\_sub\_\_, \_\_mul\_\_, and \_\_truediv\_\_).
4. Implement the remaining relational operators (\_\_gt\_\_, \_\_ge\_\_, \_\_lt\_\_, \_\_le\_\_, and \_\_ne\_\_).
5. Modify the constructor for the fraction class so that it checks to make sure that the numerator and denominator are both integers. If either is not an integer, the constructor should raise an exception.
6. In the definition of fractions we assumed that negative fractions have a negative numerator and a positive denominator. Using a negative denominator would cause some of the relational operators to give incorrect results. In general, this is an unnecessary constraint. Modify the constructor to allow the user to pass a negative denominator so that all of the operators continue to work properly.
7. Research the \_\_radd\_\_ method. How does it differ from \_\_add\_\_? When is it used? Implement \_\_radd\_\_.
8. Repeat the last question but this time consider the \_\_iadd\_\_ method.
9. Research the \_\_repr\_\_ method. How does it differ from \_\_str\_\_? When is it used? Implement \_\_repr\_\_.
"""
#Test 1
x.get_num()
assert x.get_num() == 1
y.get_den()
assert y.get_den() == 3
# Test 2
z = Fraction(3,6)
print(z) #should be 1/2
assert z == Fraction(1,2)
# Test 3
# __sub__
z = x-y
print(z)
assert z == Fraction(-1,6)
# __mul__
z = x*y
print(z)
assert z == Fraction(1,3)
# __truediv__
# from __future__ import division #this might need to be imported
z = x/y
print(z)
assert z == Fraction(3,4)
# Test 4
# __gt__
assert (x>y) == False
# __ge__
assert (x>=y) == False
# __lt__
assert (x