Complex Numbers in Java

By Xah Lee. Date:

Java does not have complex numbers. Here is a toy function that provides complex number multiplication.

class T2 {

    /**
     * complex number multiplication
     * @param a First complex number to be multiplied
     * @param b Second complex number to be multiplied
     * @return The product of a and b.
     */
    public double[] complexMultiply (double[] a, double[] b) {
        double[] prod= {a[0]*b[0] - a[1]*b[1], a[1]*b[0] + a[0]*b[1]};
        return prod;
    }
}

public class T1 {
    public static void main(String[] arg) {

        double[] c1 ={0., 1.};
        double[] c2 ={0., 1.};

        T2 x1 = new T2();
        double[] m =x1.complexMultiply(c1,c2);
        System.out.println(m[0]); // -1.0
        System.out.println(m[1]); // 0.0
    }
}

A Robust Complex Number Implementation

Here is a more robust, yet still simple, complex number implementation. From David Eck and Richard Palais. http://3D-XplorMath.org/j/index.html .

Note that, in the above, we used array of 2 elements to represent complex numbers. This is a functional approach. While in the code below, a more traditional OOP approach is used.

Go thru it, and see how in general complex numbers are implemented in Java. Try to write a sample code that calls this class and do a multiplication of two complex numbers.

package vmm.core;

/**
 * A complex number, with a real and an imaginary part.  (Possibley to be replaced with
 * a class that has better support for complex arithmetic and functions of a complex variable.)
 */
public class Complex {

  public double re, im;

  /**
   * Create a complex number initially equal to zero
   */
  public Complex() {
  }

  /**
   * Create a complex number initially equal to the real number x.
   */
  public Complex(double x) {
    re = x;
  }

  /**
   * Create a complex number initially equal to x + iy
   */
  public Complex(double x, double y) {
    re = x;
    im = y;
  }

  /**
   * Create a new complex number that is initially equal to a given complex number.
   * @param c The complex number to be copied.  If null, it is treated as zero.
   */
  public Complex(Complex c) {
    copy(c);
  }

  public static final Complex ZERO_C = new Complex(0,0);

  public static final Complex ONE_C = new Complex(1,0);

  public static final Complex I_C = new Complex(0,1);

  /**
   * Returns true if obj is equal to this complex number.  If obj is null or is not
   * of type Complex, the return value is false.
   */
  public boolean equals(Object obj) {
    try {
      Complex c = (Complex)obj;
      return c.re == re && c.im == im;
    }
    catch (Exception e) {
      return false;
    }
  }

  /**
   * Computes the conjugate of a complex number.
   */
  public Complex conj() {
    return new Complex( re, -im );
  }

  /**
   * Returns the complex number (r*cos(theta)) + i*(r*sin(theta)).
   */
  public static Complex polar(double r, double theta) {
    return new Complex(r*Math.cos(theta),r*Math.sin(theta));
  }

  /**
   * Sets this complex number equal to a copy of a given number.
   * @param c The number to be copied; if null, the number is treated as zero.
   */
  public void copy(Complex c) {
    if (c == null)
      re = im = 0;
    else {
      re = c.re;
      im = c.im;
    }
  }

  /**
   * Returns this + c; c must be non-null.
   */
  public Complex plus(Complex c) {
    return new Complex(re + c.re, im + c.im);
  }

  /**
   * Returns this - c; c must be non-null.
   */
  public Complex minus(Complex c) {
    return new Complex(re - c.re, im - c.im);
  }

  /**
   * Returns this * c; c must be non-null.
   */
  public Complex times(Complex c) {
    return new Complex(re*c.re - im*c.im, re*c.im + im*c.re);
  }

  /**
   * Returns this / c; c must be non-null.
   */
  public Complex dividedBy(Complex c) {
    double denom = c.re*c.re + c.im*c.im;
    if (denom == 0)
      return new Complex(Double.NaN,Double.NaN);
    else
      return new Complex( (re*c.re+im*c.im)/denom, (im*c.re-re*c.im)/denom);
  }

  public Complex times(double x) {
    return new Complex(re*x, im*x);
  }

  public Complex plus(double x) {
    return new Complex(re+x, im);
  }

  public Complex minus(double x) {
    return new Complex(re-x, im);
  }

  public Complex dividedBy(double x) {
    return new Complex(re/x, im/x);
  }
  /**
   * Returns the absolute value squared of this.
   * @return real part squared plus imaginary part squared
   */
  public double abs2() {
    return (re*re + im*im);
  }

  /**
   * Returns the absolute value, "r" in polar coordinates, of this.
   * @return the square root of (real part squared plus imaginary part squared)
   */
  public double r() {
    return Math.sqrt(re*re + im*im);
  }

  /**
   * Returns arg(this), the angular polar coordinate of this complex number, in the range -pi to pi.
   * The return value is simply Math.atan2(imaginary part, real part).
   */
  public double theta() {
    return Math.atan2(im,re);
  }

  /**
   * Computes the complex exponential function, e^z, where z is this complex number.
   */
  public Complex exponential() {
    double length = Math.exp(re);
    return new Complex( length*Math.cos(im), length*Math.sin(im) );
  }

  /**
   * Computes the complex reciprocal function, 1/z, where z is this complex number.
   */
  public Complex inverse() {
     double length = re*re+im*im;
    return new Complex( re/length, -im/length );
  }

  public Complex log() {
    double modulus = Math.sqrt(re*re + im*im);
    double arg = Math.atan2(im,re);
    return new Complex(Math.log(modulus), arg);
  }

  /**
   * Computes that complex logarithm of this complex number
   * that is nearest to previous.
   * A test code is in fractals.TestAnalyticContinuation.
   */
  public Complex logNearer(Complex previous) {
    Complex c = new Complex(this.log());
    double h = (c.im - previous.im)/(2*Math.PI);
    double d = (2*Math.PI)*Math.floor(h+0.5);
    c.im = c.im - d;
    return c;
  }

  public double sinh(double x) {
       return (Math.exp(x) - Math.exp(-x))/2;
  }

  public double cosh(double x) {
       return (Math.exp(x) + Math.exp(-x))/2;
  }

  public Complex sine() {
    double x, y;
    Complex z = new Complex(0.0,0.0);
    x = re;
    y = im;
    z.re = Math.sin(x) * cosh(y);
    z.im = Math.cos(x) * sinh(y);
    return z;
  }

  public Complex power(double x) {
    double modulus = Math.sqrt(re*re + im*im);
    double arg = Math.atan2(im,re);
    double log_re = Math.log(modulus);
    double log_im = arg;
    double x_log_re = x * log_re;
    double x_log_im = x * log_im;
    double modulus_ans = Math.exp(x_log_re);
    return new Complex(modulus_ans*Math.cos(x_log_im), modulus_ans*Math.sin(x_log_im));
  }

  /**
   * Returns a complex k-th root of this complex number.  The root that is returned is
   * the one with the smallest positive arg.
   * (If k is 0, the return value is 1.  If k is negative, the value is 1/integerRoot(-k).)
   */
  public Complex integerRoot(int k) {
    double a,b;
    boolean neg = false;
    if (k < 0) {
      k = -k;
      neg = true;
    }
    if (k == 0) {
      a = 1;
      b = 0;
    }
    else if (k == 1) {
      a = re;
      b = im;
    }
    else {
      double length = r();
      double angle = theta();
      if (angle < 0)
        angle += Math.PI*2;
      length = Math.pow(length,1.0/k);
      angle = angle / k;
      a = length*Math.cos(angle);
      b = length*Math.sin(angle);
    }
    if (neg) {
      double denom = a*a + b*b;
      a = a/denom;
      b = -b/denom;
    }
    return new Complex(a,b);
  }

  /**
   * Computes that square root of this complex number
   * that is nearer to previous than to minus previous.
   * A test code is in fractals.TestAnalyticContinuation.
   */
  public Complex squareRootNearer(Complex previous) {
    Complex c;
    c = this.integerRoot(2);
    if (c.re*previous.re + c.im*previous.im < 0){
      c.re=-c.re;
      c.im=-c.im;
    }
    return new Complex(c.re, c.im);
  }

  public double[] stereographicProjection() {

      double rsquare,rsquarePlusOne;
        double [] projPoint = new double[3];
        rsquare = re * re + im * im;
        rsquarePlusOne = rsquare + 1;
        projPoint[0] = (2 * re)/rsquarePlusOne;
        projPoint[1] = (2 * im)/rsquarePlusOne;
        projPoint[2] = (rsquare - 1)/rsquarePlusOne;
        return projPoint;
      }
}