CS 171 & 171L Introduction to Computer Science I & Lab Fall 2020 

Lab 6: Complex Numbers

In this lab, you will create a class that allows one to use complex numbers. You should start off with s1 driving and s2 navigating.

1. Introductions

Introduce yourself to your lab partner. What are three of your favorite songs have you listened to most (or often) in the past 12 months?

Complex Numbers

In this lab you will familiarize yourself with the java representation of objects by working with a class which supports complex numbers. For this project, you need to complete a class which performs simple operations on complex numbers. Complex numbers have many interesting properties that make them handy for many mathematical, physics, and computational tasks.

The complex number system is closed under addition, subtraction, multiplication, and division (except by 0), and taking roots. This is just some of the elegance found in the complex number system.

The Fundamental Theorem of Algebra states that every polynomial of degree \(n \ge 1\) with complex coefficients has at least one solution in the complex numbers. This means if we have such a polynomial, all solutions can be considered complex. Gauss finally proved this in 1849. He also introduced the term complex number in 1831.

Recall that there is no real number \(x\) such that \(x^2 = -1\), because the square of any real number must be nonnegative. A complex number \(z\) can be expressed as \(a + bi\), where \(a\) and \(b\) are real numbers and \(i\) is the square root of \(-1\), thus \(i^2 = -1\). If \(b = 0\), then the complex number \(z\) is real, in the same way that a real number without any digits to the right of the decimal point is an integer. Thus, we need two real numbers, an ordered pair (re, im), to represent a complex number: a real part (re) and an imaginary part (im).

Two complex numbers \(z_1 = a + b i\) and \(z_2 = c + d i \) are equal when \(a = c\) and \(b = d\), that is their real parts are equal and their imaginary parts are equal.

Because we have an ordered pair of real numbers, we can think about this as a point in the complex plane with the horizontal axis being the real axis and the vertical being the imaginary axis. We can also think about such a point in terms of polar coordinates, thus the number \(z = a + bi\) can be expressed as \((r, \theta)\) where \[r = \sqrt{a^2 + b^2}.\] and \[\theta = \tan^{-1}(b/a).\]

The term \(r\) is called the modulus of \(z\) and is often written as \(|z|\) or \(\text{mod}(z)\). The term \(\theta\) is called the argument of \(z\) and is often written as \(\arg(z)\)

A handy operation on complex numbers is called conjugatation, which negates the imaginary component. The conjugate of \(z\) is denoted \(z^*\) or \(\overline{z}\) and computed as \[z^* = a - bi.\]

Geometrically, this flips the point \(z\) about the horizontal axis. Note that \(\left(z^*\right)^* = z\). Another property of the conjugate is \[z\cdot z^* = a^2 + b^2 = |z^*|^2 = |z|^2.\]

Multiplication of the complex number \(z = a + bi\) by a real number \(s\) is given by \(s z = s a + s bi\). Addition of real \(t\) and the complex number \(z = a + bi\) is given by \(t+ z = (t+a) + bi\) (note the imaginary part is not effected).

For the two numbers to act together as one complex number, we need to define that functionality. Arithmetic operations can be performed on complex numbers using this formulation. Let \(z_1 = a + b i\) and \(z_2 = c + d i \) be complex numbers. Then \[z_1 + z_2 = \underbrace{(a + c)}_{\text{re part}} + \underbrace{(b + d)}_{\text{im part}}i.\] Subtraction is defined in a similar way. For multiplication, we have \[z_1 z_2 = (a + b i)(c + d i) = a c + a d i + b c i + b d i^2 = (ac + b d i^2) + (a d i + b c i) = \underbrace{(a c - b d)}_{\text{re part}} + \underbrace{(b c + a d)}_{\text{im part}}i. \] The division of the two complex numbers \(z_1\) and \(z_2 \) can be perfomed as follows. \[\frac{z_1}{z_2} = \frac{(a + b i)}{(c + d i) } = \frac{(a + b i) (c - d i)}{(c + d i) (c-di)} = \frac{z_1 z_2^*}{z_2 z_2^*} = \frac{(a c + b d) + (b c - a d)i}{c^2 + d^2} = \underbrace{\frac{(a c + b d)}{c^2 + d^2}}_{\text{re part}} + \underbrace{\frac{(b c - a d)}{c^2 + d^2}}_{\text{im part}}i. \]

One can also perform exponentiation. First, raising \(e\) to a complex power \(z\) is given by \[ e^z = e^{(a+bi)} = (e^a)(e^{ib}) = \left(e^a\right)\left(\cos(b) + i \sin(b)\right) = \underbrace{e^a\cos(b)}_{\text{re part}} + \underbrace{e^a\sin(b)}_{\text{im part}}i. \] Note you can use Math.exp(a) to compute \(e^a\). Interestingly, you could also use the power series expansion to also compute \(e^z\) as \[ e^z = 1 + \frac{z}{1} + \frac{z^2}{2} + \frac{z^3}{3!} + \cdots + \frac{z^k}{k!} + \frac{z^{k+1}}{(z+1)!} + \cdots = \sum_{k=0}^\infty \frac{x^k}{k!}\] Just as we did in HW 4.

Any positive real number \(x\) can be written as \(e^{\ln x}\), thus \(x^z\) can be written as \[x^z = \left(e^{\ln x}\right)^z = e^{(z \ln x)},\] which reduces to earlier solved problems.

One can compute the natural logarithm of a complex number \(z\) as \[ \ln z = \ln(|z|) + \arg(z)i = \ln\left(\sqrt{a^2 + b^2}\right) + i \tan^{-1}(b/a).\] This is the prinicpal value, because it turns out that any multiple of \(2 \pi\) added to the imaginary component will result in the same point. This is called a branch cut of the multivalued logarithm function (way beyond the scope of this course).

General exponentiation is a bit messy. Let \(z = a + b i\) and \(w = c + d i \) be complex numbers, then \(z^w\) can be performed as \[ z^w = (a + bi)^{(c+di)} = (a^2 + b^2)^{((c+di)/2)}e^{(i(c+id)\arg(a+ib))}. \]

The square root of a general real number\(x\) is given by \[ \sqrt{x} = \begin{cases} \sqrt{x} = \sqrt{x} + 0i& \text{if } x \ge 0\\ \sqrt{-x} i = 0 + \sqrt{-x} i & \text{if } x \lt 0.\\ \end{cases} \] This can also be solved by previously implemented functions using intermediate calculation.

The square root of \(z = a + b i\) is given by \[ \sqrt{z} = z^{(1/2)} = z^{(1/2 + 0i)}. \] This can also be solved by previously implemented functions using intermediate calculation.

Implementing Complex Numbers

Copy from the file the Lab6.pde into a new Processing window and save this as Lab6. Now create a new tab and call it Complex then copy the code from the Complex.pde to that window. Complete the methods in Complex.pde, as shown below. Change the driver/navigator roles after each method.

void setup() {  Complex c = new Complex();
  Complex d = new Complex(1);
  Complex e = new Complex(0, 1);
  Complex f = new Complex(2, 1);
  Complex g = new Complex(2, -1);
  Complex h = new Complex(-6, -8);
  Complex j = new Complex(h);

// Add other test cases as needed

  System.out.println("Testing constructors, equals, and printing");
  System.out.println("This should print 0: " + c);
  System.out.println("This should print 1: " + d);
  System.out.println("This should print i: " + e);
  System.out.println("This should print 2+i: " +f);
  System.out.println("This should print 2-i: " +g);
  System.out.println("This should print -6-8i: " +h);
  System.out.println("This should print -6-8i: " +j);
  System.out.println("h==h, should print true: " + (h==h));
  System.out.println("h==j, should print false: " + (h==j));
  System.out.println("h==j, should print true: " + (h.equals(j)));
  
  System.out.println();
  
  System.out.println("Testing setters and getters");
  c.setReal(9);
  c.setImaginary(8);
  System.out.println("This should print 9: " + c.getReal());
  System.out.println("This should print 8: " + c.getImaginary());
  System.out.println("This should print 9+8i: " + c);
  System.out.println();
  
  System.out.println("Testing modulus, argument, negation, conjugation");
  System.out.println("This should print 10: " + h.modulus());
  System.out.println("This should print -2.214: " + h.argument());
  System.out.println("This should print 6+8i: " + h.negate());
  System.out.println("This should print -6+8i: " + h.conjugate());
  System.out.println();
  
  System.out.println("Testing real addition and real multiplication");
  System.out.println("This should print -3-5i: " + j.add(3));
  System.out.println("This should print 3+4i: " + j.multiply(-2));
  System.out.println();
  
  System.out.println("Testing STATIC complex addition, subtraction, multiplication, and division");
  System.out.println("This should print 4: " + Complex.add(f, g));
  System.out.println("This should print 2i: " + Complex.subtract(f, g));
  System.out.println("This should print -1: " + Complex.multiply(e, e));
  System.out.println("This should print -20-10i: " + Complex.multiply(g, h));
  System.out.println();
  
  System.out.println("Testing NON-STATIC complex addition, subtraction, multiplication, and division");
  System.out.println("This should print ___: " + f.add(new Complex(5, -1)));
  System.out.println("This should print ___: " + f.subtract(new Complex(5, -1)));
  System.out.println("This should print ___: " + f.multiply(new Complex(5, -1)));
  System.out.println("This should print ___: " + f.divide(new Complex(5, -1)));
  System.out.println();
  
  System.out.println("Testing exponentiation and logarithms");
  System.out.println("This should print e^(2 pi i) = 1: " +
    Complex.exp(new Complex(0.0,2*Math.PI)));
  System.out.println("This should print e^(2 + 2 pi i) = 7.89...: " +
    Complex.exp(new Complex(2.0,2*Math.PI)));
  System.out.println("This should print 2^i: = 0.769... + 0.638...i" +
    Complex.power(2.0, new Complex(0.0,1.0)));
  System.out.println("This should print log(3+4i) = 1.609... + 0.927...i: " +
    Complex.log(new Complex(3.0,4.0)));
  System.out.println("This should print i^i - 0.207...: " +
    Complex.power(new Complex(0.0,1.0), new Complex(0.0,1.0)));
  System.out.println();
  
  System.out.println("Testing square roots");
  System.out.println("This should print sqrt(2) = 1.414...: " +
    Complex.sqrt(2));
  System.out.println("This should print sqrt(2) = 1.414...i: " +
    Complex.sqrt(-2));
  System.out.println("This should print sqrt(i) = 0.707+0.707i: " +
    Complex.sqrt(new Complex(0.0,1.0)));
}


// Represents a complex number using two doubles, 
// one for the real component and
// one for the imaginary component
public static class Complex{
  
  // variables here!
  

// Create printable format
// a+bi if b != 0 OR
// a   if b==0
public String toString() {
   return String.format("");
   }
  

// Default constructor creates 0+0i
public Complex() {
   }
   
   
// General constructor creates a+bi
public Complex(double a, double b) {
   }
   
   
// Real constructor creates a+0i
   public Complex(double a) {
   }
   
   
// Copy constructor creates a new Complex by copying z
   public Complex(Complex z) {
   }
   

public boolean equals(Complex z){
  return false;
}
   
   
// Mutator method to set real component
public void setReal(double a) {
   }

// Mutator method to set imaginary component
public void setImaginary(double b) {
   } 

// Accessor method to set imaginary component of this
public double getReal() {
  return 0.0;
   }

// Accessor method to get imaginary component of this
public double getImaginary() {
  return 0.0;
   }
   

// Accessor method to get modulus of this
// use Math.sqrt
public double modulus() {
  return 0.0;
   }

// Accessor method to get argument
// use Math.atan2
public double argument() {
  return 0.0;
   }
   
//return the negation of this
// don't change this!
public  Complex negate() {
   return new Complex();
   }

//return the conjugate of this
// don't change this!
public Complex conjugate() {
   return new Complex();
   }
   
   
// s + this
// don't change this!
public Complex add(double s) {
   return new Complex();
   }
   
// s * this
// don't change this!
public Complex multiply(double s) {
   return new Complex();
   }


// Add z1+z2 and return result
// don't change z1 or z2
public static Complex add(Complex z1, Complex z2) {
   return new Complex();
   }

// Subtract z1-z2 and return result
// don't change z1 or z2
public static Complex subtract(Complex z1, Complex z2) {
   return new Complex();
   }

// Multiply z1*z2 and return result
// don't change z1 or z2
public static Complex multiply(Complex z1, Complex z2) {
   return new Complex();
   }

// Divide z1/z2 and return result
// don't change z1 or z2
public static Complex divide(Complex z1, Complex z2) {
   return new Complex();
   }
   
   
// Add c to this Complex number
// don't change this!
public Complex add(Complex c) {
   return new Complex();
   }

// Subtract c from this Complex number
// don't change this!
public Complex subtract(Complex c) {
   return new Complex();
   }

// Multiply this Complex number by c
// don't change this!
public Complex multiply(Complex c) {
   return new Complex();
   }

// Divide this Complex number by c
// don't change this!
public Complex divide(Complex c) {
   return new Complex();
   }
   

// Compute e to the z power
// don't change z
public static Complex exp(Complex z) {
   return new Complex();
   }
   

// Compute log base e of z
// don't change z
public static Complex log(Complex z) {
   return new Complex();
   }

// Compute x to the z power
// don't change z
public static Complex power(double x, Complex z) {
   return new Complex();
   }

// Compute z to the w power
// don't change z or w
public static Complex power(Complex z, Complex w) {
   return new Complex();
   }
   

// method to get sqrt(x) of a double
public static Complex sqrt(double x) {
   return new Complex();
   }

// method to get sqrt(z)
// don't change z!
public static Complex sqrt(Complex z) {
   return new Complex();
   }
}

When you are finished, email your Complex.pde file to your lab partner and instructor.


Copyright © 2020, David A. Reimann. All rights reserved.