I'm trying to make my 'own Fraction class'.
Almost all code work fine, but at /, >, <, these are not working.
I have no idea what's wrong with my code.
def gcd(m, n):
while m%n != 0:
m, n = n, m%n
return n
class Fraction:
'''Fractional class'''
def __init__(self, num, denom):
self.num = num
self.denom = denom
def __str__(self):
return str(self.num)+'/'+str(self.denom)
def __add__(self, other):
new_num = self.num * other.denom + other.num * self.denom
new_denom = self.denom * other.denom
common = gcd(new_num, new_denom)
return Fraction(new_num//common, new_denom//common)
def __sub__(self, other):
new_num = self.num * other.denom - other.num * self.denom
new_denom = self.denom * other.denom
common = gcd(new_num, new_denom)
return Fraction(new_num//common, new_denom//common)
def __mul__(self, other):
new_num = self.num * other.num
new_denom = self.denom * other.denom
common = gcd(new_num, new_denom)
return Fraction(new_num//common, new_denom//common)
def __div__(self, other):
new_num = self.num * other.denom
new_denom = self.denom * other.num
common = gcd(new_num, new_denom)
return Fraction(new_num//common, new_denom//common)
def __equal__(self, other):
return (self.num * other.denom) == (other.num * self.denom)
def __big__(self, other):
return str(self.num * other.denom) > str(other.num * self.denom)
def __small__(self, other):
return self.num * other.denom < other.num * self.denom
if __name__ == "__main__":
f1 = Fraction(1,4)
f2 = Fraction(1,2)
print(f1+f2)
print(f1 - f2)
print(f1 * f2)
print(f1 / f2) #not working
print(f1 == f2)
print(f1 > f2) #not working
print(f1 < f2) #not working
I get the following output:
3/4
-1/4
1/8
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-50-50cad0951bd1> in <module>()
57 print(f1 - f2)
58 print(f1 * f2)
---> 59 print(f1 / f2) #not working
60
61 print(f1 == f2)
TypeError: unsupported operand type(s) for /: 'Fraction' and 'Fraction'
Am I defining __div__ correctly?
Python 3.x uses __truediv__ and __floordiv__. __div__ is used in python 2.x.
To make comparison work you need to define __lt__, __gt__, __ge__ and __le__.
Related
I am following the Runestone Academy Python3 course and tried to implement 'addition' feature for fractions using Class but I am getting error.
When I am not using GCD implementation, the code is running fine
Here is my code:
class Fraction:
def __init__(self, top, bottom):
self.num = top
self.den = bottom
def show(self):
print(f'{self.num}/{self.den}')
def __str__(self):
return f'{self.num}/{self.den}'
# adding without GCD implementation
# def __add__(self,other_fraction):
# new_num = self.num * other_fraction.den + self.den * other_fraction.num
# new_den = self.den * other_fraction.den
# return Fraction(new_num, new_den)
# adding with GCD implementation
def gcd(self, m, n):
while m % n != 0:
m, n = n, m % n
return n
def __add__(self, other_fraction):
new_num = self.num * other_fraction.den + self.den * other_fraction.num
new_den = self.den * other_fraction.den
common = gcd(new_num, new_den)
return Fraction(new_num // common, new_den // common)
# my attempt of adding two fractions by creating a method 'add'
# def add(self,other_fraction):
# new_num = self.num * other_fraction.den + self.den * other_fraction.num
# new_den = self.den * other_fraction.den
# return Fraction(new_num, new_den)
# my_fraction = Fraction(3,5)
# print(my_fraction)
# print(f'I ate {my_fraction} of my pizza')
# my_fraction.__str__()
# str(my_fraction)
f1 = Fraction(1, 4)
f2 = Fraction(1, 2)
f3 = f1 + f2
# f3 = f1.add(f2)
print(f3)
This is the error I am getting:
Traceback (most recent call last):
File "D:/Python/Mosh_Lec/app.py", line 74, in <module>
f3 = f1 + f2
File "D:/Python/Mosh_Lec/app.py", line 53, in __add__
common = gcd(new_num, new_den)
NameError: name 'gcd' is not defined
I also tried with this variation but same error:
def gcd(self, m, n):
self.num = m
self.den = n
while self.num % self.den != 0:
self.num, self.den = self.den, self.num % self.den
return self.den
The gcd method should not logically be part of the Fraction class. Indeed, you can call the gcd method with any two numbers, they do not need to be the numerator and denominator of a fraction. Therefore I would move the gcd function outside of the class.
def gcd(m, n):
...
class Fraction:
...
Look at there:
NameError: name 'gcd' is not defined
It means that it cannot find the function(or method) named gcd. Of course! It need to be called with a Fraction object, so try to change your source code at line 32:
- common = gcd(new_num, new_den)
+ common = self.gcd(new_num, new_den)
self is a Fraction object.
By the way, the method gcd that do not use the parament self should be defined as a static function:
class Fraction:
...
#staticmethod
def _gcd(m: int, n: int):
...
...
And call the method by Fraction._gcd (the underline means that it is private function(or method)).
See it's a simple issue if u see the error:
File "D:/Python/Mosh_Lec/app.py", line 53, in __add__
common = gcd(new_num, new_den)
NameError: name 'gcd' is not defined
you will see that you have defined gcd but why it is saying GCD, not defined here's the reason:
common = self.gcd(new_num, new_den)
It is as simple as that just put the above code like this:
def __add__(self, other_fraction):
new_num = self.num * other_fraction.den + self.den * other_fraction.num
new_den = self.den * other_fraction.den
common = self.gcd(new_num, new_den)
return Fraction(new_num // common, new_den // common)
and your problem is solved! Kudos!
It as simple as that.......
I'm working on a couple of basic math classes for performing line collisions in 2D.
Here is my python code:
collisions.py
import math
class Vector:
def __init__(self, x, y):
self._x = x
self._y = y
def __str__(self):
return '(%d, %d)' %(self._x, self._y)
def __add__(self, other):
return Vector(self._x + other._x, self._y + other._y)
def __sub__(self, other):
return Vector(self._x - other._x, self._y - other._y)
def __mul__(self, val):
return Vector(self._x * val, self._y * val)
# same as dot product
#def __mul__ (self, other):
# return self.dot(other)
# same as cross product
#def __pow__(self, other):
# return self.cross(other)
def x(self):
return self._x
def y(self):
return self._y
def cross(self, other):
return (self._x * other._y - self._y * other._x)
def dot(self, other):
return (self._x * other._x + self._y * other._y)
class Line:
def __init__(self, p1, p2):
self._p1 = p1
self._p2 = p2
def slope(self):
if self._p1.x() == self._p2.x():
if self._p1.y() == self._p2.y():
return str("both points coincide")
else:
if self._p1.y() < self._p2.y():
return float('inf')
else:
return float('-inf')
self._m = float((self._p2.y() - self._p1.y()) / (self._p2.x() - self._p1.x()))
return self._m
def p1(self):
return self._p1
def p2(self):
return self._p2
def LineIntersect(l1, l2):
a = l1.p1()
b = l1.p2()
c = l2.p1()
d = l2.p2()
#r = l1.p2() - l1.p1()
r = b - a
#s = l2.p2() - l2.p1()
s = d - c
d = r.cross(s)
#u = ((l2.p2.x() - l1.p1.x()) * r.y() - (l2.p2.y() - l1.p1.y()) * r.x()) / d
u = ((c.x() - a.x()) * r.y() - (c.y() - a.y()) * r.x()) / d
#t = ((l2.p2.x() - l1.p1.x()) * s.y() - (l2.p2.y() - l1.p1.y()) * s.x()) / d
t = ((c.x() - a.x()) * s.y() - (c.y() - a.y()) * s.x()) / d
if (0 <= u and u <= 1 and 0 <= t and t <= 1):
return (a + t * r)
else:
return False;
l1 = Line(Vector(0, 0), Vector(3, 3))
l2 = Line(Vector(3, 0), Vector(0, 3))
intersected = LineIntersect(l1, l2)
print(intersected)
When I run this through Windows 7 command prompt using Python 3.7's interpreter via python collisions.py
It is generating this error message:
D:\Dev\Languages\Python\Projects\Test>python collisions.py
Traceback (most recent call last):
File "collisions.py", line 88, in <module>
intersected = LineIntersect(l1, l2)
File "collisions.py", line 81, in LineIntersect
return (a + t * r)
TypeError: unsupported operand type(s) for *: 'float' and 'Vector'
I'm more inclined with the C languages specifically C++... I've been learning Python for about a year now and I'm starting to get used to it, but things like this, I understand the error message, I just don't know how to resolve them... I'm used to a strongly typed and compiled language over an interpreted language like Python.
Here I'm assuming that I have the operator within the Vector class overloaded to be able to multiply vectors by scalars... Yet Python is yelling at me that it is an unsupported operand. What can I do to resolve this issue? As a side note if you notice any other potential bugs or issues with the code please don't hesitate to mention them in a comment. I'm still learning this language!
I am having trouble creating a __div__ method in a Python class for complex numbers which should divide two complex numbers.
Here is my code:
class Complex(object):
def __init__(self, real = 0, imag = 0):
self.real = real
self.imag = imag
def __str__(self):
if self.imag > 0:
return str(self.real) + "+" + str(self.imag) + "i"
elif self.imag < 0:
return str(self.real) + str(self.imag) + "i"
def __div__(self, other):
x = self.real * other.real + self.imag * other.imag
y = self.imag * other.real - self.real * other.imag
z = other.real**2 + other.imag**2
real = x / z
imag = y / z
return Complex(real, imag)
no = Complex(2,-8)
no2 = Complex(3,7)
print(no/no2)
Unfortunately, my approach doesn't work. Any suggestions?
__div__ doesn't exist anymore in Python 3. It's been replaced by __truediv__ for / and __floordiv__ for //
Have a look at
https://docs.python.org/3/reference/datamodel.html
It's __truediv__, not __div__. __div__ was the name for the old Python 2 "floordiv for integer, truediv for non-integer" division.
While you're fixing things, you should probably add an else case in __str__.
you need to create a method __div__(self, other) where you divide the no and also a new method __opposite__(self) to change the sign when multipy,
also calling method how to devide ie no/no1 is not a god method
using #johnO solution, overwiting __truediv__
so OP can use no/no2 to division two complex numbers.
see code below
class Complex(object):
def init(self, real = 0, imag = 0):
self.real = real
self.imag = imag
def __str__(self):
if self.imag > 0:
return str(self.real) + "+" + str(self.imag) + "i"
elif self.imag < 0:
return str(self.real) + str(self.imag) + "i"
def __opposite__(self):
self.real =self.real
self.imag = self. imag if self.imag<0 else self.imag * -1
def __truediv__(self, other):
other.__opposite__()
x = self.real * other.real - self.imag * other.imag
y = self.imag * other.real + self.real * other.imag
z = other.real**2 + other.imag**2
self.new_real = x / z
self.new_imag = y / z
if self.new_imag>0:
result = "{} + {}i".format(self.new_real, self.new_imag)
else:
result = "{} {}i".format(self.new_real, self.new_imag)
return result
no = Complex(4,5)
no2 = Complex(2,6)
print(no/no2)
output
0.24 + 0.68i
I'm working through a book now and I have a question regarding one of exercises (#6).
So we have a hand-made Fraction class and, besides all other kinds of things, we want to compare two fractions.
class Fraction:
def __init__(self, num, den):
if not (isinstance(num, int) and isinstance(den, int)):
raise ValueError('Got non-int argument')
if den == 0:
raise ValueError('Got 0 denominator')
self.num = num
self.den = den
# some class methods
def __lt__(self, other):
selfnum = self.num * other.den
othernum = other.num * self.den
return selfnum < othernum
# some class methods
# trying it out
x = Fraction(1, -2)
y = Fraction(1, 3)
However, when we evaluate x < y, the result is False. I thought of making new attribute to store sign, but that messes everything up quite a bit.
Due to lack of better alternative, I added if in the method, and here's what I got
def __lt__(self, other):
selfnum = self.num * other.den
othernum = other.num * self.den
if self.den * other.den > 0:
return selfnum < othernum
else:
return selfnum > othernum
Although it seems to be working, I wonder, if there is more elegant solution.
Update
Storing sign in numerator does what I wanted (I can just change 2 lines instead of adding a conditional in each method).
If you assume that both denominators are positive, you can safely do the comparison (since a/b < c/d would imply ad < bc). I would just store the sign in the numerator:
self.num = abs(num) * (1 if num / den > 0 else -1)
self.den = abs(den)
Or:
self.num = num
self.den = den
if self.den < 0:
self.num = -self.num
self.den = -self.den
And your __lt__ method can be:
def __lt__(self, other):
return self.num * other.den < other.num * self.den
I'm trying to test my triangle class, especially at the draw_triangle function but keep getting error: "unbound method forward() must be called with Turtle instance as first argument (got int instance instead)". How do I fix that?
from __future__ import print_function, division
from math import sqrt, degrees, acos
import turtle
class Triangle():
def __init__(self, a = None, b = None, c = None):
self.a = a;
self.b = b;
self.c = c;
def is_triangle(self):
s = 0.5 * (self.a + self.b + self.c)
return (s - self.a) > 0 and (s - self.b) > 0 and (s - self.c) > 0
def perimeter(self):
return self.a + self.b + self.c
def area(self):
s = 0.5 * (self.a + self.b + self.c)
return sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))
def a_angle(self):
return degrees(acos((self.b ** 2 + self.c ** 2 - self.a ** 2) / (2.0 * self.b * self.c)))
def b_angle(self):
return degrees(acos((self.a ** 2 + self.c ** 2 - self.b ** 2) / (2.0 * self.a * self.c)))
def c_angle(self):
return degrees(acos((self.a ** 2 + self.b ** 2 - self.c ** 2) / (2.0 * self.a * self.b)))
def angles(self):
angA = a_angle(self)
angB = b_angle(self)
angC = c_angle(self)
return angA, angB, angC
def __str__(self):
return 'lengths = %d, %d, %d' % (self.a, self.b, self.c) + \
', perimeter = %d' % (perimeter(self)) + \
', area = %d' % (area(self)) + ', angles = %d' % (angles(self))
def draw_triangle(self):
window = turtle.Screen()
t = turtle.Turtle
t.forward(self.c)
t.left(180 - a_angle(self))
t.forward(self.a)
t.left(180 - b_angle(self))
t.forward(self.b)
t.done()
window.exitonclick()
if __name__ == '__main__':
triangle1 = Triangle(100,100,72)
triangle2 = Triangle(100,100,100*sqrt(2))
triangle3 = Triangle(100,50,50)
print (triangle1)
print (triangle2)
print (triangle3)
Triangle.draw_triangle(triangle1)
Triangle.draw_triangle(triangle2)
Triangle.draw_triangle(triangle3)
turtle.mainloop()
This seems to work:
from __future__ import print_function, division
from math import sqrt, degrees, acos
import turtle
class Triangle():
def __init__(self, a = None, b = None, c = None):
self.a = a;
self.b = b;
self.c = c;
def is_triangle(self):
s = 0.5 * (self.a + self.b + self.c)
return (s - self.a) > 0 and (s - self.b) > 0 and (s - self.c) > 0
def perimeter(self):
return self.a + self.b + self.c
def area(self):
s = 0.5 * (self.a + self.b + self.c)
return sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))
def a_angle(self):
return degrees(acos((self.b ** 2 + self.c ** 2 - self.a ** 2) / (2.0 * self.b * self.c)))
def b_angle(self):
return degrees(acos((self.a ** 2 + self.c ** 2 - self.b ** 2) / (2.0 * self.a * self.c)))
def c_angle(self):
return degrees(acos((self.a ** 2 + self.b ** 2 - self.c ** 2) / (2.0 * self.a * self.b)))
def angles(self):
angA = self.a_angle()
angB = self.b_angle()
angC = self.c_angle()
return angA, angB, angC
def __str__(self):
return 'lengths = %d, %d, %d' % (self.a, self.b, self.c) + \
', perimeter = %d' % (self.perimeter()) + \
', area = %d' % (self.area()) + ', angles = %d %d %d' % (self.angles())
def draw_triangle(self):
window = turtle.Screen()
t = turtle.Turtle
t.forward(self.c)
t.left(180 - self.a_angle(self))
t.forward(self.a)
t.left(180 - self.b_angle(self))
t.forward(self.b)
t.done()
window.exitonclick()
if __name__ == '__main__':
triangle1 = Triangle(100,100,72)
triangle2 = Triangle(100,100,100*sqrt(2))
triangle3 = Triangle(100,50,50)
print (triangle1)
print (triangle2)
print (triangle3)
You need "self." in front of method calls
Here is a slightly modified draw_triangle function. It runs, but probably doesn't do exactly what you want.
def draw_triangle(self):
window = turtle.Screen()
t = turtle.Turtle()
t.forward(self.c)
t.left(180 - self.a_angle())
t.forward(self.a)
t.left(180 - self.b_angle())
t.forward(self.b)
turtle.done()
window.exitonclick()
I think you should work on it a bit by yourself now.