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
Related
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!
So far, finding the hypotenuse, "side c" works fine without problems, the problem is when I try to calculate the angle, I am pretty sure it's returning a wrong value for the angle.
import math
from math import sqrt
class Triangle:
def __init__(self, side_a, side_b, ):
self.side_a = side_a
self.side_b = side_b
def SidesCalculate(self, ):
side_c = sqrt(self.side_a ** 2 + self.side_b ** 2)
return side_c
def AnglesCalculate(self, side_c):
x = math.sin(self.side_a / side_c)
math.asin(x)
x = round(x * 180 / math.pi)
return x
g = Triangle(side_a=int(input("Enter side a: ")), side_b=int(input("Enter side b: ")))
print("side c =", + g.SidesCalculate())
print("angle is =", + g.AnglesCalculate(side_c=True), '°')
Here is a way to do what you want.
First when you compute side_c, save it as an attribute.
def SidesCalculate(self, ):
self.side_c = sqrt(self.side_a ** 2 + self.side_b ** 2)
return self.side_c
Secondly, give the parameter side_c a default value None. (You also have another math error in the following function pointed by CFLS)
def AnglesCalculate(self, side_c = None):
if side_c == None:
side_c = self.side_c
x = math.asin(self.side_a / side_c)
x = round(x * 180 / math.pi)
return x
Now, if you want the class to pick previously computed side_c, you can do this:
g = Triangle(side_a=int(input("Enter side a: ")), side_b=int(input("Enter side b: ")))
print("side c =", + g.SidesCalculate())
print("angle is =", + g.AnglesCalculate(), '°')
def AnglesCalculate(self, side_c):
x = math.asin(self.side_a / side_c)
x = round(x * 180 / math.pi)
return x
I am currently working on creating a Polynomial class that includes add , mul and eval methods. I'm currently stuck on the addition portion, if someone could give me some help on how to get that figured out that would be greatly appreciated. Everything currently works without errors but when I do p3 = p1 + p2 and I print p3 I get back the two lists together. Any feedback would be greatly appreciated.
class Polynomial(object):
def __init__(self, *coeffs, num = 0):
self.coeffs = list(coeffs) # turned into a list
assert (type(num) is type(1))
self.num = num
# Needs to be operator overload
'''
def __mul__(self, other):
'''
def __eval__(self, other, coeff, x):
result = coeff[-1]
for i in range(-2, -len(coeff)-1, -1):
result = result * x + coeff[i]
return result
def __add__(self, other):
assert type(other) is Polynomial
num = self.coeffs + other.coeffs
return Polynomial(num)
def __sub__(self, other):
assert type(other) is Polynomial
num = self.coeffs - other.coeffs
return Polynomial(num)
def __represntation__(self):
return "Polynomial" + str(self.coeffs)
def __str__(self):
rep = ""
degree = len(self.coeffs) - 1
rep += str(self.coeffs[0]) + "x^" + str(degree)
for i in range(1, len(self.coeffs)-1):
coeff = self.coeffs[i]
if coeff < 0:
rep += " - " + str(-coeff) + "x^" + str(degree - i)
else:
rep += " + " + str(coeff) + "x^" + str(degree - i)
if self.coeffs[-1] < 0:
rep += " - " + str(-self.coeffs[-1])
else:
rep += " + " + str(self.coeffs[-1])
return rep
You cannot directly add two lists.
def __add__(self, other):
assert type(other) is Polynomial
assert len(self.coeffs) != len(other.coeffs)
new_ceffs = [item1 + item2 for (item1, item2) in zip(self.coeffs, other.coeffs)]
return Polynomial(new_ceffs)
The problem is here:
num = self.coeffs + other.coeffs
Adding one list to another list concatenates them. To simply add corresponding elements to each other, you'd want to do
from itertools import zip_longest
...
num = [a + b for (a, b) in zip_longest(self.coeffs, other.coeffs, fillvalue=0)]
We use zip_longest() instead of the more generic zip() because one polynomial is possibly longer than the other and we don't want to ruin it. Either one of them will group together the corresponding elements so that we can easily add them and make a list of those.
You would do something similar for subtraction.
you should reverse the order of coefficients passed to your constructor so that indexes in the self.coeffs list correspond to the exponents. This would simplify the rest of your code and allow you to use zip_longest for additions and subtractions.
When you get to other operations however, I think you will realize that your internal structure would be easier to manage if it was a dictionary. A dictionary is more permissive of missing entries thus avoiding preoccupations of allocating spaces for new indexes.
class Polynomial(object):
def __init__(self, *coeffs):
self.coeffs = {exp:c for exp,c in enumerate(coeffs[::-1])}
def __add__(self, other):
assert type(other) is Polynomial
result = Polynomial(0)
result.coeffs = {**self.coeffs}
for exp,c in other.coeffs.items():
result.coeffs[exp] = result.coeffs.get(exp,0) + c
return result
def __sub__(self, other):
assert type(other) is Polynomial
result = Polynomial(0)
result.coeffs = {**self.coeffs}
for exp,c in other.coeffs.items():
result.coeffs[exp] = result.coeffs.get(exp,0) - c
return result
def __mul__(self, other):
assert type(other) is Polynomial
result = Polynomial(0)
for exp1,c1 in self.coeffs.items():
for exp2,c2 in other.coeffs.items():
result.coeffs[exp1+exp2] = result.coeffs.get(exp1+exp2,0) + c1*c2
return result
def __representation__(self):
return "Polynomial" + str(self.coeffs)
def __str__(self):
result = [""]+[f"{c}x^{i}" for i,c in sorted(self.coeffs.items()) if c]+[""]
result = "+".join(reversed(result))
result = result.replace("+1x","+x")
result = result.replace("-1x","-x")
result = result.replace("x^0","")
result = result.replace("x^1+","x+")
result = result.replace("+-","-")
result = result.strip("+")
result = result.replace("+"," + ")
result = result[:1]+result[1:].replace("-"," - ")
return result.strip()
I need to make some functions that perform basic algebraic operations and a couple of other things on quaternions(these are basically complex numbers of the form a + xi + yj + z*k). I first created a class which contain some attributes, and whenever i create an instance with it I get a quaternion. However, when I tried implementing the functions I mentioned before I keep getting error messages. Anyway, here is my code in its full:
from math import *
class Quaternion(object):
def __init__(self, re, xc, yc, zc):
self.a = re
self.x = xc
self.y = yc
self.z = zc
def __str__(self):
return str(self.a) + "+" + str(self.x) + "i" + "+" + str(self.y) + "j" + "+" + str(self.z) + "k"
def add(self, q):
self.a = self.a + q.a
self.x = self.x + q.x
self.y = self.y + q.y
self.z = self.z + q.z
def mul(self, q):
self.a = self.a*q.a - self.x*q.x - self.y*q.y - self.z*q.z
self.x = self.a*q.x + self.x*q.a + self.y*q.z - self.z*q.y
self.y = self.a*q.y + self.y*q.a + self.z*q.x - self.x*q.z
self.z = self.a*q.z + self.z*q.a + self.x*q.y - self.y*q.x
def conjugate(self):
self.a = self.a
self.x = -1 * self.x
self.y = -1 * self.y
self.z = -1 * self.z
def norm(self):
return sqrt((self.a)**2+(self.x)**2+(self.y)**2+(self.z)**2)
def reciprocal(self):
p1 = self.conjugate()
self.a = p1.a * (1/(self.norm())**2)
self.x = p1.x * (1/(self.norm())**2)
self.y = p1.y * (1/(self.norm())**2)
self.z = p1.z * (1/(self.norm())**2)
def main():
p = Quaternion(2, 0, -3, 0)
q = Quaternion(0, 1, 1, -2)
print "p =", p
print "q =", q
print "p + q =", p.add(q)
print "p * q =", p.mul(q)
print "conjugate of p is", p.conjugate()
print "norm of p is", p.norm()
print "reciprocal of p is", p.reciprocal()
print "p x reciprocal(p) =", p.mul(p.reciprocal)
if __name__ == '__main__':
main()
Now, whenever I run the module(so it then executes the commands under the main function), I get this:
p = 2+0i+-3j+0k
q = 0+1i+1j+-2k
p + q = None
p * q = None
conjugate of p is None
norm of p is 9.11043357914
reciprocal of p is
The only thing it does right is printing out the two quaternions p and q, but none of the other functions/methods seem to be working properly(the norm does give a value, but it isnt the right one for some reason).
Before I forget, let me quickly say what each functions needs to do:
add(self, q) needs to add 2 quaternions together.
mul(self, q) needs to multiply 2 quaternions.
conjugate(self) needs to transform a given quaternion a + xi + yj + zk into this form: a - xi - yj - zk.
norm(self) and reciprocal(self) need to respectively return the norm and reciprocal of the quaternion
You are performing the math correctly in principle, but you are not returning a new object where you should be.
For example, let's look at add(). When you sum two objects, you are expecting the return value to be a third object of the same type, which you are printing. Your add() function does not return anything (in Python this is equivalent to returning None), and instead unexpectedly modifies the object it is called on. Instead, do this:
def add(self, q):
return Quaternion(self.a + q.a,
self.x + q.x,
self.y + q.y,
self.z + q.z)
Do the same for the other methods. If you want to use + and * operators in your code, change the method names to __add__ and __mul__. To do in-place addition and multiplication using += and *= operators, sort of like your current methods are doing, rename the current methods to __iadd__ and __imul__, but don't forget to return self at the end.
You get the None values because you did not specify a return value. Add a
return self
at the end of add, mul, conjugate and reciprocal. (If it is intended that these methods change the value of p, and do not just compute a new Quaternion while leaving p untouched.)
I have written a class to work with three dimensional vectors as follows
class vector(object):
def __init__(self, x=None, y=None, z=None, angle=None):
if angle == None:
self.x, self.y, self.z = x, y, z
if angle != None:
if angle == "rad":
self.r, self.theta, self.phi = x, y, z
if angle == "deg":
self.r = x
self.theta = y * 2 * pi / 360.
self.phi = z * 2 * pi / 360.
self.x = self.r * sin(self.theta) * cos(self.phi)
self.y = self.r * sin(self.theta) * sin(self.phi)
self.z = self.r * cos(self.theta)
def write(self):
file.write("[" + str(self.x) + ",\t" + str(self.y) + ",\t" + str(self.z) + "]")
def write_sph(self):
file.write("[" + str(self.mag()) + ",\t" + str(self.gettheta()) + ",\t" + str(self.getphi()) + "]")
def getx(self):
return self.x
def gety(self):
return self.y
def getz(self):
return self.z
def setx(self, x):
self.x = x
def sety(self, y):
self.y = y
def setz(self, z):
self.z = z
def square(self):
return self.x*self.x + self.y*self.y + self.z*self.z
def mag(self):
return sqrt(self.square())
def gettheta(self):
return arccos(self.z / self.mag())
def getphi(self):
return arctan2(self.y, self.x) # sign depends on which quadrant the coordinates are in
def __add__(self, vector(other)):
v_sum = vector(other.gettx() + self.gettx(), other.getty() + self.getty(), other.getty() + self.getty())
return v_sum
In the last definition I am attempting to override the operator for addition. The definition works by calling a new vector named other and adding its x,y,z components to the corresponding components of self. When I run the code I'm told the syntax for the definition is invalid. How do I correctly define the vector argument for this overriding definition? Also what difference would changing the definition from def __ add __ to simply def add make? i.e what do the underscores denote?
You shouldn't have vector(other) in your parameter list - just say other. Also, you'll need to fix the typos in the add method:
def __add__(self, other):
v_sum = vector(other.getx() + self.getx(), other.gety() + self.gety(), other.getz() + self.getz())
return v_sum