/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
* Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
* This source code is released under a BSD License, which allows redistribution
* in source and binary form, with or without modification, provided copyright
* and license information are included, and with no warranty or guarantee of
* any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
*/
package vmm3d.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 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);
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) {
if (c != null) {
re = c.re;
im = c.im;
}
}
/**
* 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));
}
/**
* 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);
}
/**
* z.realLinComb(a,b,c) returns a*z+b*c, double a,b;
*/
public Complex realLinComb(double a, double b, Complex c) {
return new Complex(a*re + b*c.re, a*im + b*c.im);
}
/**
* z.complexLinComb(a,b,c) returns a*z+b*c, Complex a,b;
*/
public Complex complexLinComb(Complex a, Complex b, Complex c) {
return new Complex(this.times(a).plus(c.times(b)));
}
/**
* z.dot(c) returns the scalar product z.re*c.re + z.im*c.im
*/
public double dot(Complex c) {
return (re*c.re + im*c.im);
}
/**
* 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() {
Complex result;
double length = re*re+im*im;
if (length == 0)
result = new Complex(Double.NaN, Double.NaN);
else
result = new Complex( re/length, -im/length);
return result;
}
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 new Complex(this^k), for |k|< 9 using multiplication, for larger |k| using exp(k*log(this))
*/
public Complex integerPower(int k) {
double a,b,aux,bux,auy,buy;
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 if (k == 2) {
a = re*re-im*im;
b = 2*re*im;
}
else if (k == 3) {
aux = re*re-im*im;
bux = 2*re*im;
a = re*aux - im*bux;
b = re*bux + im*aux;
}
else if (k == 4) {
aux = re*re-im*im;
bux = 2*re*im;
a = aux*aux - bux*bux;
b = 2*aux*bux;
}
else if (k == 5) {
aux = re*re-im*im;
bux = 2*re*im;
auy = aux*aux - bux*bux;
buy = 2*aux*bux;
a = re*auy - im*buy;
b = re*buy + im*auy;
}
else if (k == 6) {
aux = re*re-im*im;
bux = 2*re*im;
auy = aux*aux - bux*bux;
buy = 2*aux*bux;
a = aux*auy - bux*buy;
b = aux*buy + bux*auy;
}
else if (k == 7) {
aux = re*re-im*im;
bux = 2*re*im;
a = aux*aux - bux*bux;
b = 2*aux*bux;
auy = aux*a - bux*b;
buy = aux*b + bux*a;
a = auy*re - buy*im;
b = auy*im + buy*re;
}
else if (k == 8) {
aux = re*re-im*im;
bux = 2*re*im;
auy = aux*aux - bux*bux;
buy = 2*aux*bux;
a = auy*auy - buy*buy;
b = 2*auy*buy;
}
else if (k == 9) {
aux = re*re-im*im;
bux = 2*re*im;
auy = aux*aux - bux*bux;
buy = 2*aux*bux;
aux = auy*auy - buy*buy;
bux = 2*auy*buy;
a = re*aux - im*bux;
b = re*bux + im*aux;
}
else if (k == 10) {
aux = re*re-im*im;
bux = 2*re*im;
auy = aux*aux - bux*bux;
buy = 2*aux*bux;
aux = re*auy - im*buy;
bux = re*buy + im*auy;
a = aux*aux - bux*bux;
b = 2*aux*bux;
}
else {
double length = r();
double angle = theta();
if (angle < 0)
angle += Math.PI*2;
length = Math.pow(length,k);
angle = angle * k;
a = length*Math.cos(angle);
b = length*Math.sin(angle);
}
if (neg) {
double denom = a*a + b*b;
if (denom==0)
{ a = Double.NaN; b = Double.NaN; }
else {
a = a/denom;
b = -b/denom; }
}
return new Complex(a,b);
}
/**
* 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;
if (denom==0)
{ a = Double.NaN; b = Double.NaN; }
else {
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);
}
/**
* The Moebius transformation ((1+r)z + r)/(rz + 1+r) has +1,-1 as fixed points.
* It maps the real line and the unit circle to itsself
*/
public Complex mobius1_1(double r){
Complex wd = this.times(r);
Complex wn = wd.plus(this);
wd.re = wd.re + 1+r;
wn.re = wn.re + r;
return wn.dividedBy(wd);
}
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;
}
public void assign( double x, double y ) {
re=x;
im=y;
}
/**
* Returns a string representation of the form a, i, -i, i*b, -i*b, a + i, a - i, a + i*b, or a - i*b.
* (Except when the real or imaginary part is undefined or infinite, the form is
* "(re) + i*(im)" where NaN, +INF, and -INF are used to indicate undefined and infinite values.)
*/
public String toString() {
if (Double.isNaN(re) || Double.isNaN(im) || Double.isInfinite(re) || Double.isInfinite(im)) {
String reStr = Double.isNaN(re) ? "NaN" : re == Double.POSITIVE_INFINITY ? "+INF" : re == Double.NEGATIVE_INFINITY ? "-INF" : "" + re;
String imStr = Double.isNaN(im) ? "NaN" : im == Double.POSITIVE_INFINITY ? "+INF" : im == Double.NEGATIVE_INFINITY ? "-INF" : "" + im;
return "(" + reStr + ") + i*(" + imStr + ")";
}
else if (im == 0)
return "" + re;
else if (im < 0) {
if (re == 0)
return im == -1 ? "-i" : "-i*" + (-im);
else
return re + (im == -1 ? " - i" : " - i*" + (-im));
}
else {
if (re == 0)
return im == 1 ? "i" : "i*" + im;
else
return re + (im == 1 ? " + i" : " + i*" + im);
}
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// The following methods were added because they are used in
// several classes written by Hermann Karcher.
public void assign(Complex c) {
re = c.re;
im = c.im;
}
public double det(Complex c) {
return re * c.im - im * c.re;
}
public void assignTimes(double d) {
re *= d;
im *= d;
}
public void assignInvert() {
double length = re*re+im*im;
re = re/length;
im = -im/length;
}
public void assignPow(Complex z, double x) {
double modulus = Math.sqrt(z.re*z.re + z.im*z.im);
double arg = Math.atan2(z.im,z.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);
re = modulus_ans*Math.cos(x_log_im);
im = modulus_ans*Math.sin(x_log_im);
}
public void assignPlus(Complex a, Complex b) {
re = a.re + b.re;
im = a.im + b.im;
}
public void assignPlus(Complex c) {
re += c.re;
im += c.im;
}
public void assignMinus(Complex c) {
re += -c.re;
im += -c.im;
}
public void assignTimes(Complex c, double d) {
re = c.re*d;
im = c.im*d;
}
public void assignTimes(Complex c) {
double new_re = re*c.re - im*c.im;
im = re*c.im + im*c.re;
re = new_re;
}
public void assignTimes(Complex a, Complex b) {
re = a.re*b.re - a.im*b.im;
im = a.re*b.im + a.im*b.re;
}
public void assignDivide(Complex c) {
double denom = c.re*c.re + c.im*c.im;
double new_re = (re*c.re+im*c.im)/denom;
im = (im*c.re-re*c.im)/denom;
re = new_re;
}
public void assignTimesTimes(Complex a, double d) {
assignTimes(a);
assignTimes(d);
}
public void assignPlusTimes(Complex a, Complex b) {
assignPlus(a);
assignTimes(b);
}
public void assignTimesPlus(Complex a, Complex b) {
assignTimes(a);
assignPlus(b);
}
public void assign_PlusTimes(Complex a, Complex b) {
re += a.re*b.re - a.im*b.im;
im += a.re*b.im + a.im*b.re;
}
public void assign_PlusTimes(Complex a, double d) {
re += a.re*d;
im += a.im*d;
}
public void assignTimes_PlusTimes(Complex a, Complex b, double d) {
assignTimes(a);
re += b.re*d;
im += b.im*d;
}
public Complex invert() {
return inverse();
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Ads help maintain this website.