This project is meant to follow the Fraction project. If you haven't done it yet, stop and go back to it! At the bottom, you'll find examples that make use of complex numbers built from fractions.
You'll need of course to know what complex numbers are and how to work with them. I've written a primer. Please do read.
Call it cnum.
Call the attributes of objects in this class rp and ip, for "real part" and "imaginary part" respectively.
A call to the cnum class should send one or two numbers (that could be floats, ints or fracs). The first should become the value of self.rp. The second, if sent, should become the value of self.ip; and if no second value is sent, it should default to 0.
You'll of course want to write yourself a nice __repr__ method. See the examples below.
Teach Python to add, subtract, multiply and divide complex numbers. Teach Python how to raise a complex number to an integer power. You'll overload built-in methods just as you did with the frac class. See the primer linked above for definitions of these operations.
Also define negation and absolute value. Note that the absolute value of a complex number is its magnitude. The primer linked above defines that.
You need not define any comparison operators other than equality and inequality. Two complex numbers are equal just when their real parts are equal and their imaginary parts are equal. As the real the imaginary parts are often floats, you should use an appropriate "approximately equal" test.
Be sure that the class handles operations in which only one of the two operands is complex. For instance, it should handle both cnum + float and float + cnum. (How? You'll override both __add__ and __radd__; and in both, you'll convert the float to a cnum.)
As with the frac class, do not mutate a complex number once its been created; that is, do not change its real or its imaginary part. Instead when you perform some operation with complex numbers, create and return a new complex number. Like this:
def __add__(self, second):
    real_part = self.rp + second.rp
    imag_part = self.ip + second.ip
    return cnum(real_part, imag_part)
# I kept my class in a separate file named cnum.py
import cnum
c1 = cnum.cnum(1, 1)
print("Here's a complex number:", c1)
print("Here's its type:", type(c1))
print()
c2 = cnum.cnum(2, 3)
c3 = c1 + c2
print("Add: ", end = "")
print(c1, "+", c2, "=", c3)
print()
c4 = c1 * c2
print("Multiply: ", end = "")
print(c1, "*", c2, "=", c4)
print()
c5 = -c1
print("The negation of", c1, "is", c5)
print()
# Subtraction is addition of the negative
c6 = c1 - c2
print("Subtract: ", end = "")
print(c1, "-", c2, "=", c6)
print()
print("The conjugate of", c2, "is", c2.conj())
print()
c7 = c1 / c2
print("Division: ", end = "")
print(c1, "/", c2, "=", c7)
print()
print(c1, "raised to powers 1, 2, 3 and 4:", c1, c1 ** 2, c1 ** 3, c1 ** 4)
print(c1, "raised to powers -1 and -2:", c1 ** -1, c1 ** -2)
print("(3 + 4i) ** 5 = ", cnum.cnum(3, 4) ** 5)
print()
print("The magnitude of", c1, "is", abs(c1))
print()
print("Operations with Reals")
print("2 +", c1, "=", 2 + c1)
print(c1, "+ 2 =", c1 + 2)
print("2 -", c1, "=", 2 - c1)
print(c1, "- 2 =", c1 - 2)
print("2 /", c1, "=", 2 / c1)
print(c1, "/ 2 =", c1 / 2)
print()
print("Equality Tests")
print(c1 == c1, c1 != c1)
print(1 == c1, c1 == 1)
print(1 != c1, c1 != 1)
print()
print("Chained Operations")
c10 = cnum.cnum(5, 12)
c11 = cnum.cnum(12, 15)
c12 = cnum.cnum(3, 18)
c13 = cnum.cnum(15, 1)
print((c12 + c13) ** (-2) / (c10 + c11) ** (-3))
Output:
Here's a complex number: (1 + 1i)
Here's its type: <class 'cnum.cnum'>
Add: (1 + 1i) + (2 + 3i) = (3 + 4i)
Multiply: (1 + 1i) * (2 + 3i) = (-1 + 5i)
The negation of (1 + 1i) is (-1 + -1i)
Subtract: (1 + 1i) - (2 + 3i) = (-1 + -2i)
The conjugate of (2 + 3i) is (2 + -3i)
Division: (1 + 1i) / (2 + 3i) = (0.38461538461538464 + -0.07692307692307693i)
(1 + 1i) raised to powers 1, 2, 3 and 4: (1 + 1i) (0 + 2i) (-2 + 2i) (-4 + 0i)
(1 + 1i) raised to powers -1 and -2: (0.5 + -0.5i) (0.0 + -0.5i)
(3 + 4i) ** 5 =Â (-237 + -3116i)
The magnitude of (1 + 1i) is 1.4142135623730951
Operations with Reals
2 + (1 + 1i) = (3 + 1i)
(1 + 1i) + 2 = (3 + 1i)
2 - (1 + 1i) = (1 + -1i)
(1 + 1i) - 2 = (-1 + 1i)
2 / (1 + 1i) = (1.0 + -1.0i)
(1 + 1i) / 2 = (0.5 + 0.5i)
Equality Tests
True False
False False
True True
Chained Operations
(7.975760029836433 + 46.74107730832756i)
Let's put fracs and cnums together.
import frac, cnum
f1 = frac.frac(1, 2)
f2 = frac.frac(2, 3)
f3 = frac.frac(1, 3)
f4 = frac.frac(3, 4)
c1 = cnum.cnum(f1, f2)
c2 = cnum.cnum(f3, f4)
print("Comp Nums with Frac Parts")
print(c1, c2)
print()
print("Add")
print(c1 + c2)
print()
print("Subtract")
print(c1 - c2)
print()
print("Multiply")
print(c1 * c2)
print()
print("Division")
print(c1 / c2)
print()
print("Negation")
print(-c1)
print()
print("Exponentiation")
print(c1 ** 3)
print()
print("Magnitude")
print(abs(c1))
print()
print("Comparison")
f1 = frac.frac(3, 12)
f2 = frac.frac(2, 8)
f3 = frac.frac(2, 12)
f4 = frac.frac(3, 18)
f5 = frac.frac(1, 5)
c1 = cnum.cnum(f1, f3)
c2 = cnum.cnum(f2, f4)
c3 = cnum.cnum(f1, f5)
print(c1 == c2, c1 == c3, c1 != c2, c1 != c3)
Output:
Comp Nums with Frac Parts
(1/2 + 2/3i) (1/3 + 3/4i)
Add
(5/6 + 17/12i)
Subtract
(1/6 + -1/12i)
Multiply
(-1/3 + 43/72i)
Division
(96/97 + -22/97i)
Negation
(-1/2 + -2/3i)
Exponentiation
(-13/24 + 11/54i)
Magnitude
0.8333333333333334
Comparison
True False False True