package com.nr; /* File: Complex.java * -- A Java class for performing complex * number arithmetic to double precision. * * Copyright (c) 1997 - 2001, Alexander Anderson. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ import java.io.Serializable; /** *
* @version
* 1.0.1
*
* Last change: ALM 23 Mar 2001 8:56 pm
*
*
* A Java class for performing complex number arithmetic to double * precision. * *
*
* This applet has been adapted
from a Vector
* Visualization applet by Vladimir Sorokin.
*
* @author Sandy Anderson * @author Priyantha Jayanetti *
*
*
* Copyright (c) 1997 - 2001, Alexander Anderson.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
*
*
* The latest version of this Complex class is available from * the Netlib Repository. *
* Here's an example of the style the class permits:
*
*
* import ORG.netlib.math.complex.Complex;* *
* public class Test {
* public boolean isInMandelbrot (Complex c, int maxIter) { * Complex z= new Complex(0, 0);
* for (int i= 0; i < maxIter; i++) { * z= z.mul(z).add(c); * if (z.abs() > 2) return false; * }
* return true; * }
* } *
*
*
*
**/ public class Complex implements Cloneable, Serializable { private static final long serialVersionUID = 1L; public static final String VERSION = "1.0.1"; public static final String DATE = "Fri 23-Mar-2001 8:56 pm"; public static final String AUTHOR = "sandy@almide.demon.co.uk"; public static final String REMARK = "Class available from " + "http://www.netlib.org/"; /** * Switches on debugging information. *
**/ // protected static boolean debug = false; /** * Whilst debugging: the nesting level when tracing method calls. *
**/ // private static int trace_nesting = 0; /** * Twice PI * radians is the same thing as 360 degrees. *
**/ protected static final double TWO_PI = 2.0 * Math.PI; /** * A constant representing i, the famous square root of * -1. *
* The other square root of -1 is - i. *
**/ public static final Complex I = new Complex(0.0, 1.0); // private static long objectCount; // !!! private double re; private double im; //---------------------------------// // CONSTRUCTORS // //---------------------------------// /** * Constructs a Complex representing the number zero. * *
**/ public Complex () { this(0.0, 0.0); }//end Complex() /** * Constructs a Complex representing a real number. * *
* @param re The real number *
* @see Complex#real(double) **/ public Complex (double re) { this(re, 0.0); }//end Complex(double) /** * Constructs a separate new Complex from an existing * Complex. * *
* @param z A Complex number *
**/ public Complex (Complex z) { this(z.re, z.im); }//end Complex(Complex) /** * Constructs a Complex from real and imaginary parts. * *
* Note: All methods in class
* Complex which deliver a Complex are written such that
* no intermediate Complex objects get generated. This means that
* you can easily anticipate the likely effects on garbage collection caused
* by your own coding.
*
*
* @param re Real part * @param im Imaginary part *
* @see Complex#cart(double, double) * @see Complex#polar(double, double) **/ public Complex (double re, double im) { this.re = re; this.im = im; // if (debug) System.out.println(indent(trace_nesting) + "new Complex, #" + (++objectCount));// !!! }//end Complex(double,double) //---------------------------------// // DEBUG // //---------------------------------// /* // BETA Debugging methods... private static void entering (String what) { System.out.print(indent(trace_nesting) + what); trace_nesting++; }//end entering(String) private static void enter (String what, double param1, double param2) { entering(what); System.out.println("(" + param1 + ", " + param2 + ") "); }//end enter(String,double,double) private static void enter (String what, double param) { entering(what); System.out.println("(" + param + ") "); }//end enter(String,double) private static void enter (String what, Complex z) { entering(what); System.out.println("(" + z + ") "); }//end enter(String,Complex) private static void enter (String what, Complex z1, Complex z2) { entering(what); System.out.println("(" + z1 + ", " + z2 + ") "); }//end enter(String,Complex,Complex) private static void enter (String what, Complex z, double x) { entering(what); System.out.println("(" + z + ", " + x + ") "); }//end enter(String,Complex,double) private static void enter (String what, Complex z, double x, double y) { entering(what); System.out.println("(" + z + ", " + cart(x, y) + ") "); }//end enter(String,Complex,double) private static void enter (String what, Complex z1, Complex z2, double x) { entering(what); System.out.println("(" + z1 + ", " + z2 + ", " + x + ") "); }//end enter(String,Complex,Complex,double) private static void leaving (String what) { trace_nesting--; System.out.print(indent(trace_nesting) + "is "); }//end leaving(String) private static void leave (String what, boolean result) { leaving(what); System.out.println(result); }//end leave(String,boolean) private static void leave (String what, double result) { leaving(what); System.out.println(result); }//end leave(String,double) private static void leave (String what, Complex result) { leaving(what); System.out.println(result); }//end leave(String,Complex) private static String indent (int nesting) { StringBuffer indention = new StringBuffer(""); for (int i = 0; i < nesting; i++) { indention.append(" "); }//endfor return indention.toString(); }//end indent(int) */ /** * Useful for checking up on the exact version. * *
**/ public static void main (String[] args) { System.out.println(); System.out.println("Module : " + Complex.class.getName()); System.out.println("Version: " + Complex.VERSION); System.out.println("Date : " + Complex.DATE); System.out.println("Author : " + Complex.AUTHOR); System.out.println("Remark : " + Complex.REMARK); System.out.println(); System.out.println("Hint: use TestComplex to test the class."); System.out.println(); }//end main(String[]) //---------------------------------// // STATIC // //---------------------------------// /** * Returns a Complex representing a real number. * *
* @param real The real number *
* @return Complex representation of the real *
* @see Complex#re() * @see Complex#cart(double, double) **/ public static Complex real (double real) { return new Complex(real, 0.0); }//end real(double) /** * Returns a Complex from real and imaginary parts. * *
* @param re Real part * @param im Imaginary part *
* @return Complex from Cartesian coordinates *
* @see Complex#re() * @see Complex#im() * @see Complex#polar(double, double) * @see Complex#toString() **/ public static Complex cart (double re, double im) { return new Complex(re, im); }//end cart(double,double) /** * Returns a Complex from a size and direction. * *
* @param r Size * @param theta Direction (in radians) *
* @return Complex from Polar coordinates *
* @see Complex#abs() * @see Complex#arg() * @see Complex#cart(double, double) **/ public static Complex polar (double r, double theta) { if (r < 0.0) { theta += Math.PI; r = -r; }//endif theta = theta % TWO_PI; return cart(r * Math.cos(theta), r * Math.sin(theta)); }//end polar(double,double) /** * Returns the Complex base raised to the power of the exponent. * *
* @param base The base "to raise" * @param exponent The exponent "by which to raise" *
* @return base "raised to the power of" exponent *
* @see Complex#pow(double, Complex) **/ public static Complex pow (Complex base, double exponent) { // return base.log().scale(exponent).exp(); double re = exponent * Math.log(base.abs()); double im = exponent * base.arg(); double scalar = Math.exp(re); return cart( scalar * Math.cos(im), scalar * Math.sin(im) ); }//end pow(Complex,double) /** * Returns the base raised to the power of the Complex exponent. * *
* @param base The base "to raise" * @param exponent The exponent "by which to raise" *
* @return base "raised to the power of" exponent *
* @see Complex#pow(Complex, Complex) * @see Complex#exp() **/ public static Complex pow (double base, Complex exponent) { // return real(base).log().mul(exponent).exp(); double re = Math.log(Math.abs(base)); double im = Math.atan2(0.0, base); double re2 = (re*exponent.re) - (im*exponent.im); double im2 = (re*exponent.im) + (im*exponent.re); double scalar = Math.exp(re2); return cart( scalar * Math.cos(im2), scalar * Math.sin(im2) ); }//end pow(double,Complex) /** * Returns the Complex base raised to the power of the Complex exponent. * *
* @param base The base "to raise" * @param exponent The exponent "by which to raise" *
* @return base "raised to the power of" exponent *
* @see Complex#pow(Complex, double) * @see Complex#pow(Complex) **/ public static Complex pow (Complex base, Complex exponent) { // return base.log().mul(exponent).exp(); double re = Math.log(base.abs()); double im = base.arg(); double re2 = (re*exponent.re) - (im*exponent.im); double im2 = (re*exponent.im) + (im*exponent.re); double scalar = Math.exp(re2); return cart( scalar * Math.cos(im2), scalar * Math.sin(im2) ); }//end pow(Complex,Complex) //---------------------------------// // PUBLIC // //---------------------------------// /** * Returns true if either the real or imaginary component of this * Complex is an infinite value. * *
* @return true if either component of the Complex object is infinite; false, otherwise. *
**/ public boolean isInfinite () { return ( Double.isInfinite(re) || Double.isInfinite(im) ); }//end isInfinite() /** * Returns true if either the real or imaginary component of this * Complex is a Not-a-Number (NaN) value. * *
* @return true if either component of the Complex object is NaN; false, otherwise. *
**/ public boolean isNaN () { return ( Double.isNaN(re) || Double.isNaN(im) ); }//end isNaN() /** * Decides if two Complex numbers are "sufficiently" alike to be * considered equal. * *
* tolerance is the maximum magnitude of the difference between * them before they are considered not equal. *
* Checking for equality between two real numbers on computer hardware is a * tricky business. Try *
*
System.out.println((1.0/3.0 * 3.0));*
* and you'll see the nature of the problem! It's just as tricky with * Complex numbers. *
* Realize that because of these complications, it's possible to find that * the magnitude of one Complex number a is less than * another, b, and yet a.equals(b, myTolerance) returns * true. Be aware! *
* @param z The Complex to compare with * @param tolerance The tolerance for equality *
* @return true, or false *
**/ public boolean equals (Complex z, double tolerance) { // still true when _equal_ to tolerance? ... return abs(re - z.re, im - z.im) <= Math.abs(tolerance); // ...and tolerance is always non-negative }//end equals(Complex,double) /** * Test for the equality of two Complex objects. * If both the real and imaginary parts of two complex numbers * are exactly the same, and neither is {@code Double.NaN}, the two * Complex objects are considered to be equal. * All {@code NaN} values are considered to be equal - i.e, if either * (or both) real and imaginary parts of the complex number are equal * to {@code Double.NaN}, the complex number is equal to * {@code NaN}. * * @param other Object to test for equality to this * @return true if two Complex objects are equal, false if object is * {@code null}, not an instance of Complex, or not equal to this Complex * instance. */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (other instanceof Complex){ Complex c = (Complex)other; if (c.isNaN()) { return c.isNaN(); } else { return (re == c.re) && (im == c.im); } } return false; } /** * Returns a hashcode for this complex number. */ public int hashCode() { return (int)(Math.exp(mod())); } /** * Overrides the {@link java.lang.Cloneable Cloneable} interface. * *
* Standard override; no change in semantics. *
* The following Java code example illustrates how to clone, or copy, a * Complex number: *
*
* Complex z1 = new Complex(0, 1); * Complex z2 = (Complex) z1.clone(); **
* @return An Object that is a copy of this Complex object. *
* @see java.lang.Cloneable * @see java.lang.Object#clone() **/ public Object clone () { try { return (Object)(super.clone()); } catch (java.lang.CloneNotSupportedException e) { return null; // This cannot happen: there would have to be a serious internal error in the Java runtime if this codepath happens! }//endtry }//end clone() /** * Extracts the real part of a Complex as a double. * *
*
* re(x + i*y) = x **
* @return The real part *
* @see Complex#im() * @see Complex#cart(double, double) * @see Complex#real(double) **/ public double re () { return re; }//end re() /** * Extracts the imaginary part of a Complex as a double. * *
*
* im(x + i*y) = y **
* @return The imaginary part *
* @see Complex#re() * @see Complex#cart(double, double) **/ public double im () { return im; }//end im() /** * Returns the square of the "length" of a Complex number. * *
*
* norm(x + i*y) = x*x + y*y **
* Always non-negative. *
* @return The norm *
* @see Complex#abs() **/ public double norm () { return (re*re) + (im*im); }//end norm() /** * Returns the magnitude of a Complex number. * *
*
* abs(z) = sqrt(norm(z)) **
* In other words, it's Pythagorean distance from the origin * (0 + 0i, or zero). *
* The magnitude is also referred to as the "modulus" or "length". *
* Always non-negative. *
* @return The magnitude (or "length") *
* @see Complex#arg() * @see Complex#polar(double, double) * @see Complex#norm() **/ public double abs () { return abs(re, im); }//end abs() public double mod () { return abs(re, im); }//end mod() static private double abs (double x, double y) { // abs(z) = sqrt(norm(z)) // Adapted from // "Numerical Recipes in Fortran 77: The Art of Scientific Computing" // (ISBN 0-521-43064-X) double absX = Math.abs(x); double absY = Math.abs(y); if (absX == 0.0 && absY == 0.0) { // !!! Numerical Recipes, mmm? return 0.0; } else if (absX >= absY) { double d = y / x; return absX*Math.sqrt(1.0 + d*d); } else { double d = x / y; return absY*Math.sqrt(1.0 + d*d); }//endif }//end abs() /** * Returns the principal angle of a Complex number, in * radians, measured counter-clockwise from the real axis. (Think of the * reals as the x-axis, and the imaginaries as the y-axis.) * *
* There are infinitely many solutions, besides the principal solution. * If A is the principal solution of arg(z), the others are of * the form: *
*
* A + 2*k*PI **
* where k is any integer. *
* arg() always returns a double between * -PI and +PI. *
* Note: 2*PI radians is the same as 360 degrees.
*
*
* Domain Restrictions: There are no restrictions: the
* class defines arg(0) to be 0
*
*
* @return Principal angle (in radians) *
* @see Complex#abs() * @see Complex#polar(double, double) **/ public double arg () { return Math.atan2(im, re); }//end arg() /** * Returns the "negative" of a Complex number. * *
*
* neg(a + i*b) = -a - i*b **
* The magnitude of the negative is the same, but the angle is flipped * through PI (or 180 degrees). *
* @return Negative of the Complex *
* @see Complex#scale(double) **/ public Complex neg () { return this.scale(-1.0); }//end neg() /** * Returns the Complex "conjugate". * *
*
* conj(x + i*y) = x - i*y **
* The conjugate appears "flipped" across the real axis. *
* @return The Complex conjugate *
**/ public Complex conj () { return cart(re, -im); }//end conj() static private void inv (Complex z) { double zRe, zIm; double scalar; if (Math.abs(z.re) >= Math.abs(z.im)) { scalar = 1.0 / ( z.re + z.im*(z.im/z.re) ); zRe = scalar; zIm = scalar * (- z.im/z.re); } else { scalar = 1.0 / ( z.re*(z.re/z.im) + z.im ); zRe = scalar * ( z.re/z.im); zIm = - scalar; }//endif z.re = zRe; z.im = zIm; }//end inv(Complex) /** * Returns the Complex scaled by a real number. * *
*
* scale((x + i*y), s) = (x*s + i*y*s) **
* Scaling by the real number 2.0, doubles the magnitude, but leaves * the arg() unchanged. Scaling by -1.0 keeps the magnitude * the same, but flips the arg() by PI (180 degrees). *
* @param scalar A real number scale factor *
* @return Complex scaled by a real number *
* @see Complex#mul(Complex) * @see Complex#div(Complex) * @see Complex#neg() **/ public Complex scale (double scalar) { return cart(scalar*re, scalar*im); }//end scale(double) public Complex mul (double scalar) { return cart(scalar*re, scalar*im); }//end scale(double) /** * To perform z1 + z2, you write z1.add(z2) . * *
*
* (a + i*b) + (c + i*d) = ((a+c) + i*(b+d)) **
**/ public Complex add (Complex z) { return cart(re + z.re, im + z.im); }//end add(Complex) /** * To perform z1 - z2, you write z1.sub(z2) . * *
*
* (a + i*b) - (c + i*d) = ((a-c) + i*(b-d)) **
**/ public Complex sub (Complex z) { return cart(re - z.re, im - z.im); }//end sub(Complex) /** * To perform z1 * z2, you write z1.mul(z2) . * *
*
* (a + i*b) * (c + i*d) = ( (a*c) - (b*d) + i*((a*d) + (b*c)) ) **
* @see Complex#scale(double) **/ public Complex mul (Complex z) { return cart( (re*z.re) - (im*z.im), (re*z.im) + (im*z.re) ); // return cart( (re*z.re) - (im*z.im), (re + im)*(z.re + z.im) - re*z.re - im*z.im); }//end mul(Complex) /** * To perform z1 / z2, you write z1.div(z2) . * *
*
* (a + i*b) / (c + i*d) = ( (a*c) + (b*d) + i*((b*c) - (a*d)) ) / norm(c + i*d) **
* Take care not to divide by zero! *
* Note: Complex arithmetic in Java never causes
* exceptions. You have to deliberately check for overflow, division by
* zero, and so on, for yourself.
*
*
* Domain Restrictions: z1/z2 is undefined if z2 = 0
*
*
* @see Complex#scale(double) **/ public Complex div (Complex z) { Complex result = new Complex(this); div(result, z.re, z.im); return result; }//end div(Complex) public Complex div(final double x) { return new Complex(re/x,im/x); } static private void div (Complex z, double x, double y) { // Adapted from // "Numerical Recipes in Fortran 77: The Art of Scientific Computing" // (ISBN 0-521-43064-X) double zRe, zIm; double scalar; if (Math.abs(x) >= Math.abs(y)) { scalar = 1.0 / ( x + y*(y/x) ); zRe = scalar * (z.re + z.im*(y/x)); zIm = scalar * (z.im - z.re*(y/x)); } else { scalar = 1.0 / ( x*(x/y) + y ); zRe = scalar * (z.re*(x/y) + z.im); zIm = scalar * (z.im*(x/y) - z.re); }//endif z.re = zRe; z.im = zIm; }//end div(Complex,double,double) /** * Returns a Complex representing one of the two square roots. * *
*
* sqrt(z) = sqrt(abs(z)) * ( cos(arg(z)/2) + i * sin(arg(z)/2) ) **
* For any complex number z, sqrt(z) will return the * complex root whose arg is arg(z)/2. *
* Note: There are always two square roots for each
* Complex number, except for 0 + 0i, or zero. The other
* root is the neg() of the first one. Just as the two roots of
* 4 are 2 and -2, the two roots of -1 are i and - i.
*
*
* @return The square root whose arg is arg(z)/2. *
* @see Complex#pow(Complex, double)
**/
public Complex
sqrt () {
Complex result = new Complex(this);
sqrt(result);
return result;
}//end sqrt()
static private void
sqrt (Complex z) {
// with thanks to Jim Shapiro
* @param exponent The exponent "by which to raise"
*
* @return this Complex "raised to the power of" the exponent
*
* @see Complex#pow(Complex, Complex)
**/
public Complex
pow (Complex exponent) {
return Complex.pow(this, exponent);
}//end pow(Complex)
/**
* Returns the number e "raised to" a Complex power.
*
*
*
* Note:
*
* Also, the following is quietly amazing:
*
* @return e "raised to the power of" this Complex
*
* @see Complex#log()
* @see Complex#pow(double, Complex)
**/
public Complex
exp () {
double scalar = Math.exp(re); // e^ix = cis x
return cart( scalar * Math.cos(im), scalar * Math.sin(im) );
}//end exp()
/**
* Returns the principal natural logarithm of a Complex
* number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If L is the principal solution of log(z), the others are of
* the form:
*
*
* where k is any integer.
*
* @return Principal Complex natural logarithm
*
* @see Complex#exp()
**/
public Complex
log () {
return cart( Math.log(this.abs()), this.arg() ); // principal value
}//end log()
/**
* Returns the principal logarithm (base 10) of a
* Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If L is the principal solution of log10(z), the others are
* of the form:
*
*
* where k is any integer.
*
* @return Principal Complex logarithm (base 10)
*
* @see Complex#exp()
* @see Complex#log()
**/
/* DEPRECATED !!!
public Complex
log10 () {
Complex result;
// if (debug) enter("log10", this);
double scalar = 1.0/Math.log(10.0);
// result = this.log().scale(scalar);
result = cart( scalar * Math.log(this.abs()), scalar * this.arg() );
// if (debug) leave("log10", result);
return result;
}//end log10()
/* */
/**
* Returns the sine of a Complex number.
*
*
*
* @return The Complex sine
*
* @see Complex#asin()
* @see Complex#sinh()
* @see Complex#cosec()
* @see Complex#cos()
* @see Complex#tan()
**/
public Complex
sin () {
Complex result;
// sin(z) = ( exp(i*z) - exp(-i*z) ) / (2*i)
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _1: _1.sub(_2) ...
_re1 = _re1 - _re2; // !!!
_im1 = _im1 - _im2; // !!!
// result: _1.div(2*i) ...
result = cart( 0.5*_im1, -0.5*_re1 );
// ... result = cart(_re1, _im1);
// div(result, 0.0, 2.0);
return result;
}//end sin()
/**
* Returns the cosine of a Complex number.
*
*
*
* @return The Complex cosine
*
* @see Complex#acos()
* @see Complex#cosh()
* @see Complex#sec()
* @see Complex#sin()
* @see Complex#tan()
**/
public Complex
cos () {
Complex result;
// cos(z) = ( exp(i*z) + exp(-i*z) ) / 2
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _1: _1.add(_2) ...
_re1 = _re1 + _re2; // !!!
_im1 = _im1 + _im2; // !!!
// result: _1.scale(0.5) ...
result = cart( 0.5 * _re1, 0.5 * _im1 );
return result;
}//end cos()
/**
* Returns the tangent of a Complex number.
*
*
*
* Domain Restrictions:
* @return The Complex tangent
*
* @see Complex#atan()
* @see Complex#tanh()
* @see Complex#cot()
* @see Complex#sin()
* @see Complex#cos()
**/
public Complex
tan () {
Complex result;
// tan(z) = sin(z) / cos(z)
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
double _re3, _im3;
double cs_re, cs_im;
// sin() ...
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _3: _1.sub(_2) ...
_re3 = _re1 - _re2;
_im3 = _im1 - _im2;
// result: _3.div(2*i) ...
result = cart( 0.5*_im3, -0.5*_re3 );
// result = cart(_re3, _im3);
// div(result, 0.0, 2.0);
// cos() ...
// _3: _1.add(_2) ...
_re3 = _re1 + _re2;
_im3 = _im1 + _im2;
// cs: _3.scale(0.5) ...
cs_re = 0.5 * _re3;
cs_im = 0.5 * _im3;
// result: result.div(cs) ...
div(result, cs_re, cs_im);
return result;
}//end tan()
/**
* Returns the cosecant of a Complex number.
*
*
*
* Domain Restrictions:
* @return The Complex cosecant
*
* @see Complex#sin()
* @see Complex#sec()
* @see Complex#cot()
**/
public Complex
cosec () {
Complex result;
// cosec(z) = 1 / sin(z)
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _1: _1.sub(_2) ...
_re1 = _re1 - _re2; // !!!
_im1 = _im1 - _im2; // !!!
// _result: _1.div(2*i) ...
result = cart( 0.5*_im1, -0.5*_re1 );
// result = cart(_re1, _im1);
// div(result, 0.0, 2.0);
// result: one.div(_result) ...
inv(result);
return result;
}//end cosec()
/**
* Returns the secant of a Complex number.
*
*
*
* Domain Restrictions:
* @return The Complex secant
*
* @see Complex#cos()
* @see Complex#cosec()
* @see Complex#cot()
**/
public Complex
sec () {
Complex result;
// sec(z) = 1 / cos(z)
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _1: _1.add(_2) ...
_re1 = _re1 + _re2;
_im1 = _im1 + _im2;
// result: _1.scale(0.5) ...
result = cart(0.5*_re1, 0.5*_im1);
// result: one.div(result) ...
inv(result);
return result;
}//end sec()
/**
* Returns the cotangent of a Complex number.
*
*
*
* Domain Restrictions:
* @return The Complex cotangent
*
* @see Complex#tan()
* @see Complex#cosec()
* @see Complex#sec()
**/
public Complex
cot () {
Complex result;
// cot(z) = 1 / tan(z) = cos(z) / sin(z)
double scalar;
double iz_re, iz_im;
double _re1, _im1;
double _re2, _im2;
double _re3, _im3;
double sn_re, sn_im;
// cos() ...
// iz: i.mul(z) ...
iz_re = -im;
iz_im = re;
// _1: iz.exp() ...
scalar = Math.exp(iz_re);
_re1 = scalar * Math.cos(iz_im);
_im1 = scalar * Math.sin(iz_im);
// _2: iz.neg().exp() ...
scalar = Math.exp(-iz_re);
_re2 = scalar * Math.cos(-iz_im);
_im2 = scalar * Math.sin(-iz_im);
// _3: _1.add(_2) ...
_re3 = _re1 + _re2;
_im3 = _im1 + _im2;
// result: _3.scale(0.5) ...
result = cart( 0.5*_re3, 0.5*_im3 );
// sin() ...
// _3: _1.sub(_2) ...
_re3 = _re1 - _re2;
_im3 = _im1 - _im2;
// sn: _3.div(2*i) ...
sn_re = 0.5 * _im3; // !!!
sn_im = - 0.5 * _re3; // !!!
// result: result.div(sn) ...
div(result, sn_re, sn_im);
return result;
}//end cot()
/**
* Returns the hyperbolic sine of a Complex number.
*
*
*
* @return The Complex hyperbolic sine
*
* @see Complex#sin()
* @see Complex#asinh()
**/
public Complex
sinh () {
Complex result;
// sinh(z) = ( exp(z) - exp(-z) ) / 2
double scalar;
double _re1, _im1;
double _re2, _im2;
// _1: z.exp() ...
scalar = Math.exp(re);
_re1 = scalar * Math.cos(im);
_im1 = scalar * Math.sin(im);
// _2: z.neg().exp() ...
scalar = Math.exp(-re);
_re2 = scalar * Math.cos(-im);
_im2 = scalar * Math.sin(-im);
// _1: _1.sub(_2) ...
_re1 = _re1 - _re2; // !!!
_im1 = _im1 - _im2; // !!!
// result: _1.scale(0.5) ...
result = cart( 0.5 * _re1, 0.5 * _im1 );
return result;
}//end sinh()
/**
* Returns the hyperbolic cosine of a Complex number.
*
*
*
* @return The Complex hyperbolic cosine
*
* @see Complex#cos()
* @see Complex#acosh()
**/
public Complex
cosh () {
Complex result;
// cosh(z) = ( exp(z) + exp(-z) ) / 2
double scalar;
double _re1, _im1;
double _re2, _im2;
// _1: z.exp() ...
scalar = Math.exp(re);
_re1 = scalar * Math.cos(im);
_im1 = scalar * Math.sin(im);
// _2: z.neg().exp() ...
scalar = Math.exp(-re);
_re2 = scalar * Math.cos(-im);
_im2 = scalar * Math.sin(-im);
// _1: _1.add(_2) ...
_re1 = _re1 + _re2; // !!!
_im1 = _im1 + _im2; // !!!
// result: _1.scale(0.5) ...
result = cart( 0.5 * _re1, 0.5 * _im1 );
return result;
}//end cosh()
/**
* Returns the hyperbolic tangent of a Complex number.
*
*
*
* @return The Complex hyperbolic tangent
*
* @see Complex#tan()
* @see Complex#atanh()
**/
public Complex
tanh () {
Complex result;
// tanh(z) = sinh(z) / cosh(z)
double scalar;
double _re1, _im1;
double _re2, _im2;
double _re3, _im3;
double ch_re, ch_im;
// sinh() ...
// _1: z.exp() ...
scalar = Math.exp(re);
_re1 = scalar * Math.cos(im);
_im1 = scalar * Math.sin(im);
// _2: z.neg().exp() ...
scalar = Math.exp(-re);
_re2 = scalar * Math.cos(-im);
_im2 = scalar * Math.sin(-im);
// _3: _1.sub(_2) ...
_re3 = _re1 - _re2;
_im3 = _im1 - _im2;
// result: _3.scale(0.5) ...
result = cart(0.5*_re3, 0.5*_im3);
// cosh() ...
// _3: _1.add(_2) ...
_re3 = _re1 + _re2;
_im3 = _im1 + _im2;
// ch: _3.scale(0.5) ...
ch_re = 0.5 * _re3;
ch_im = 0.5 * _im3;
// result: result.div(ch) ...
div(result, ch_re, ch_im);
return result;
}//end tanh()
/**
* Returns the principal arc sine of a Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of asin(z), the others are
* of the form:
*
*
* where k is any integer.
*
* @return Principal Complex arc sine
*
* @see Complex#sin()
* @see Complex#sinh()
**/
public Complex
asin () {
Complex result;
// asin(z) = -i * log(i*z + sqrt(1 - z*z))
double _re1, _im1;
// _1: one.sub(z.mul(z)) ...
_re1 = 1.0 - ( (re*re) - (im*im) );
_im1 = 0.0 - ( (re*im) + (im*re) );
// result: _1.sqrt() ...
result = cart(_re1, _im1);
sqrt(result);
// _1: z.mul(i) ...
_re1 = - im;
_im1 = + re;
// result: _1.add(result) ...
result.re = _re1 + result.re;
result.im = _im1 + result.im;
// _1: result.log() ...
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: i.neg().mul(_1) ...
result.re = _im1;
result.im = - _re1;
return result;
}//end asin()
/**
* Returns the principal arc cosine of a Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of acos(z), the others are
* of the form:
*
*
* where k is any integer.
*
* @return Principal Complex arc cosine
*
* @see Complex#cos()
* @see Complex#cosh()
**/
public Complex
acos () {
Complex result;
// acos(z) = -i * log( z + i * sqrt(1 - z*z) )
double _re1, _im1;
// _1: one.sub(z.mul(z)) ...
_re1 = 1.0 - ( (re*re) - (im*im) );
_im1 = 0.0 - ( (re*im) + (im*re) );
// result: _1.sqrt() ...
result = cart(_re1, _im1);
sqrt(result);
// _1: i.mul(result) ...
_re1 = - result.im;
_im1 = + result.re;
// result: z.add(_1) ...
result.re = re + _re1;
result.im = im + _im1;
// _1: result.log()
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: i.neg().mul(_1) ...
result.re = _im1;
result.im = - _re1;
return result;
}//end acos()
/**
* Returns the principal arc tangent of a Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of atan(z), the others are
* of the form:
*
*
* where k is any integer.
*
* Domain Restrictions:
* @return Principal Complex arc tangent
*
* @see Complex#tan()
* @see Complex#tanh()
**/
public Complex
atan () {
Complex result;
// atan(z) = -i/2 * log( (i-z)/(i+z) )
double _re1, _im1;
// result: i.sub(z) ...
result = cart(- re, 1.0 - im);
// _1: i.add(z) ...
_re1 = + re;
_im1 = 1.0 + im;
// result: result.div(_1) ...
div(result, _re1, _im1);
// _1: result.log() ...
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: half_i.neg().mul(_2) ...
result.re = 0.5*_im1;
result.im = -0.5*_re1;
return result;
}//end atan()
/**
* Returns the principal inverse hyperbolic sine of a
* Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of asinh(z), the others are
* of the form:
*
*
* where k is any integer.
*
* @return Principal Complex inverse hyperbolic sine
*
* @see Complex#sinh()
**/
public Complex
asinh () {
Complex result;
// asinh(z) = log(z + sqrt(z*z + 1))
double _re1, _im1;
// _1: z.mul(z).add(one) ...
_re1 = ( (re*re) - (im*im) ) + 1.0;
_im1 = ( (re*im) + (im*re) ) + 0.0;
// result: _1.sqrt() ...
result = cart(_re1, _im1);
sqrt(result);
// result: z.add(result) ...
result.re = re + result.re; // !
result.im = im + result.im; // !
// _1: result.log() ...
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: _1 ...
result.re = _re1;
result.im = _im1;
/*
* Many thanks to the mathematicians of aus.mathematics and sci.math,
* and to Zdislav V. Kovarik of the Department of Mathematics and
* Statistics, McMaster University and John McGowan
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of acosh(z), the others are
* of the form:
*
*
* where k is any integer.
*
* @return Principal Complex inverse hyperbolic cosine
*
* @see Complex#cosh()
**/
public Complex
acosh () {
Complex result;
// acosh(z) = log(z + sqrt(z*z - 1))
double _re1, _im1;
// _1: z.mul(z).sub(one) ...
_re1 = ( (re*re) - (im*im) ) - 1.0;
_im1 = ( (re*im) + (im*re) ) - 0.0;
// result: _1.sqrt() ...
result = cart(_re1, _im1);
sqrt(result);
// result: z.add(result) ...
result.re = re + result.re; // !
result.im = im + result.im; // !
// _1: result.log() ...
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: _1 ...
result.re = _re1;
result.im = _im1;
return result;
}//end acosh()
/**
* Returns the principal inverse hyperbolic tangent of a
* Complex number.
*
*
*
* There are infinitely many solutions, besides the principal solution.
* If A is the principal solution of atanh(z), the others are
* of the form:
*
*
* where k is any integer.
*
* Domain Restrictions:
* @return Principal Complex inverse hyperbolic tangent
*
* @see Complex#tanh()
**/
public Complex
atanh () {
Complex result;
// atanh(z) = 1/2 * log( (1+z)/(1-z) )
double _re1, _im1;
// result: one.add(z) ...
result = cart(1.0 + re, + im);
// _1: one.sub(z) ...
_re1 = 1.0 - re;
_im1 = - im;
// result: result.div(_1) ...
div(result, _re1, _im1);
// _1: result.log() ...
_re1 = Math.log(result.abs());
_im1 = result.arg();
// result: _1.scale(0.5) ...
result.re = 0.5 * _re1;
result.im = 0.5 * _im1;
return result;
}//end atanh()
/**
* Converts a Complex into a {@link java.lang.String String} of the form
* (a + bi).
*
*
* This enables a Complex to be easily printed. For example, if
* z was 2 - 5i, then
*
* @return {@link java.lang.String String} containing the cartesian coordinate representation
*
* @see Complex#cart(double, double)
**/
public String
toString () {
StringBuffer result = new StringBuffer("(");
result.append(re);
if (im < 0.0) { // ...remembering NaN & Infinity
result.append(" - ").append(-im);
} else if (1.0 / im == Double.NEGATIVE_INFINITY) {
result.append(" - ").append(0.0);
} else {
result.append(" + ").append(+im);
}//endif
result.append("i)");
return result.toString();
}//end toString()
/*
I know a young man called Daniel,
When you meet him, you'll like him, and you'll
Find him so true, so human and new,
You'll want to live life with no manual.
*/
}//end Complex
/* Jim Shapiro
* exp(x + i*y) = exp(x) * ( cos(y) + i * sin(y) )
*
* The value of e, a transcendental number, is
* roughly 2.71828182846...
*
* ePI*i = - 1
*
*
*
*
* log(z) = log(abs(z)) + i * arg(z)
*
*
* L + (2*k*PI)*i
*
*
* log10(z) = log(z) / log(10)
*
*
* L + (2*k*PI)*i
*
*
* sin(z) = ( exp(i*z) - exp(-i*z) ) / (2*i)
*
*
* cos(z) = ( exp(i*z) + exp(-i*z) ) / 2
*
*
* tan(z) = sin(z) / cos(z)
*
* tan(z) is undefined whenever z = (k + 1/2) * PI
*
* where k is any integer
*
* cosec(z) = 1 / sin(z)
*
* cosec(z) is undefined whenever z = k * PI
*
* where k is any integer
*
* sec(z) = 1 / cos(z)
*
* sec(z) is undefined whenever z = (k + 1/2) * PI
*
* where k is any integer
*
* cot(z) = 1 / tan(z)
*
* cot(z) is undefined whenever z = k * PI
*
* where k is any integer
*
* sinh(z) = ( exp(z) - exp(-z) ) / 2
*
*
* cosh(z) = ( exp(z) + exp(-z) ) / 2
*
*
* tanh(z) = sinh(z) / cosh(z)
*
*
* asin(z) = -i * log(i*z + sqrt(1 - z*z))
*
*
* k*PI + (-1)k * A
*
*
* acos(z) = -i * log( z + i * sqrt(1 - z*z) )
*
*
* 2*k*PI +/- A
*
*
* atan(z) = -i/2 * log( (i-z)/(i+z) )
*
*
* A + k*PI
*
* atan(z) is undefined for z = + i or z = - i
*
*
* asinh(z) = log(z + sqrt(z*z + 1))
*
*
* k*PI*i + (-1)k * A
*
*
* acosh(z) = log(z + sqrt(z*z - 1))
*
*
* 2*k*PI*i +/- A
*
*
* atanh(z) = 1/2 * log( (1+z)/(1-z) )
*
*
* A + k*PI*i
*
* atanh(z) is undefined for z = + 1 or z = - 1
*
*
* System.out.println("z = " + z);
*
* would print something like
*
* z = (2.0 - 5.0i)
*
*
*