Complex Number Class

Do frac First

This project is meant to follow the frac project. If you haven't done frac yet, stop and go back to it! At the bottom, you'll find examples that makes use of complex numbers built from fractions.

Complex Numbers: A  Primer

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.

The Complex Number Class

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)

Complex Number Tests

# 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)

Together

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