Skip to content

Instantly share code, notes, and snippets.

@cab1729
Last active November 1, 2022 02:51
Show Gist options
  • Save cab1729/1349284 to your computer and use it in GitHub Desktop.
Save cab1729/1349284 to your computer and use it in GitHub Desktop.
Code Samples - Core Java/Math: Complex Numbers/Functions
import java.io.Serializable;
import java.util.Formattable;
import java.util.Formatter;
/**
* Complex number class. A Complex consists of a real and imaginary
* part of type {@link double}.<p>
*
* Note: The methods inherited from <code>Number</code> return
* the value of the real part of the complex number.
*
* main reference: Schaum's Outlines - Complex Variables
*
* @author Jose Menes
*/
public class Complex extends Number
implements Formattable, Serializable {
/**
*
*/
private static final long serialVersionUID = -7417547029717136577L;
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int NONE = -1;
public static final Complex I = new Complex(ZERO, ONE);
public static final Complex nI = new Complex(ZERO, NONE);
public static final Complex e = new Complex(StrictMath.E, ZERO);
public static final long INFINITE = Long.MAX_VALUE;
public Complex(double real)
{
this(real, ZERO);
}
public Complex(double real, double imag)
{
this.real = real;
this.imag = imag;
}
/**
* @return real part of complex number
*/
public double real()
{
return this.real;
}
/**
* @return imaginary part of complex number
*/
public double imag()
{
return this.imag;
}
/**
* add two complex numbers
* @param z - complex number to add to this number
* @return
*/
public Complex add(Complex z)
{
return new Complex(
this.real + z.real(), this.imag + z.imag());
}
/**
* subtract two complex numbers
* @param z - complex number to subtract from this number
* @return
*/
public Complex subtract(Complex z)
{
return new Complex(
this.real - z.real(), this.imag - z.imag());
}
/**
* multiply two complex numbers
* @param z - complex number to multiply by
* @return
*/
public Complex multiply(Complex z)
{
// if both Im(this) and Im(z) are zero use double arithmetic
if (this.imag == 0. || z.imag() == 0.)
{
return new Complex(this.real*z.real());
}
return new Complex(
(this.real*z.real()) - (this.imag* z.imag()),
(this.real*z.imag()) + (this.imag* z.real()));
}
/**
* Divide two complex numbers
* @param z - the complex denominator/divisor
* @return
*/
public Complex divide(Complex z)
{
double c = z.real();
double d = z.imag();
// check for Re,Im(z) == 0 to avoid +/-infinity in result
double zreal2 = 0.0;
if (c != 0.0)
{
zreal2 = StrictMath.pow(c, 2.);
}
double zimag2 = 0.0;
if (d != 0.0)
{
zimag2 = StrictMath.pow(d, 2.);
}
double ac = this.real*c;
double bd = this.imag*d;
double bc = this.imag*c;
double ad = this.real*d;
return new Complex((ac+bd)/(zreal2+zimag2),(bc-ad)/(zreal2+zimag2));
}
/**
* @param z
* @return true if z == this
*/
public boolean equals(Complex z)
{
if (this.real == z.real() || this.imag == z.imag())
{
return true;
}
return false;
}
/**
* Return the square modulus of a complex number z
* @param z
* @return
*/
public static double abs(Complex z)
{
return
StrictMath.sqrt(StrictMath.pow(z.real(), 2) + StrictMath.pow(z.imag(), 2));
}
/**
* return the complex angle of z
* (value returned should be between -Pi and Pi)
* @param z
* @return
*/
public static double arg(Complex z)
{
double theta = StrictMath.atan2(z.imag(),z.real());
return theta;
}
/**
* Exponentiation (e^a+bi)
* @param z
* @return <code>e<sup>z</sup></code>.
*/
public static Complex exp(Complex z)
{
if (z.imag() == 0.0)
return new Complex(StrictMath.exp(z.real()),ONE);
Complex ex = new Complex(StrictMath.exp(z.real()), ZERO);
return ex.multiply(
new Complex(StrictMath.cos(z.imag()), StrictMath.sin(z.imag())));
}
/**
* Complex power
* @param z - the complex base
* @param y - the complex exponent
* @return
*/
public static Complex pow(Complex z, Complex y)
{
double c = y.real();
double d = y.imag();
// get polar of base
double r = Complex.abs(z);
double theta = Complex.arg(z);
Complex f1 = new Complex(
(StrictMath.pow(r, c)*StrictMath.pow(StrictMath.E, -d*theta)),ZERO);
Complex f2 =
new Complex(
StrictMath.cos(d*StrictMath.log(r)+c*theta),
StrictMath.sin(d*StrictMath.log(r)+c*theta));
return f1.multiply(f2);
}
/**
* @return complex conjugate
*/
public Complex conjugate()
{
return new Complex(this.real, -1*this.imag);
}
/**
* @return negative of complex
*/
public Complex neg()
{
if (this.imag != 0)
return new Complex(-1*this.real, -1*this.imag);
else
return new Complex(-1*this.real);
}
/**
* Return the given complex number multiplied by i
* @param complex number z
* @return
*/
public static Complex Iz(Complex z)
{
Complex result;
if (z.imag() != 0.0)
result = new Complex(-1.*z.imag(), z.real());
else
result = new Complex(z.imag(), z.real());
return result;
}
/**
* Return the given complex number multiplied by -i
* @param complex number z
* @return
*/
public static Complex nIz(Complex z)
{
Complex result;
if (z.real() != 0.0)
result = new Complex(z.imag(), -1*z.real());
else
result = new Complex(z.imag(), z.real());
return result;
}
@Override
public double doubleValue() {
// TODO Auto-generated method stub
return Double.valueOf(this.real);
}
@Override
public float floatValue() {
// TODO Auto-generated method stub
return Float.parseFloat(Double.toString(this.real));
}
@Override
public int intValue() {
// TODO Auto-generated method stub
return Integer.parseInt(Double.toString(this.real));
}
@Override
public long longValue() {
// TODO Auto-generated method stub
return Long.parseLong(Double.toString(this.real));
}
public void formatTo(Formatter arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
throw new NoSuchMethodError();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.valueOf(real) + " " + String.valueOf(imag) + "i";
}
private double real;
private double imag;
}
/**
* Complex number functions. A Complex consists of a real and imaginary
* part of type {@link double}.<p>
* main reference: Schaum's Outlines - Complex Variables
*
* @author Jose Menes
*/
public class ComplexFunctions {
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int NONE = -1;
public static final Complex one = new Complex(1.);
public static final Complex I = new Complex(ZERO, ONE);
public static final Complex nI = I.neg();
public static final Complex e = new Complex(StrictMath.E, ZERO);
public static final long INFINITE = Long.MAX_VALUE;
public static final double Pi = StrictMath.PI;
private static int INFINITY = 1000;
private ComplexFunctions()
{
// prevent instantiation
}
/**
* Return the square modulus of a complex number z
* @param z
* @return
*/
public static double abs(Complex z)
{
return
StrictMath.hypot(z.real(), z.imag());
}
/**
* return the complex angle of z
* (value returned should be between -Pi and Pi)
* @param z
* @return
*/
public static double arg(Complex z)
{
return StrictMath.atan2(z.imag(),z.real());
}
/**
* Exponentiation (e^a+bi)
* @param z
* @return <code>e<sup>z</sup></code>.
*/
public static Complex exp(Complex z)
{
if (z.imag() == 0.0)
return new Complex(StrictMath.exp(z.real()),ONE);
Complex ex = new Complex(StrictMath.exp(z.real()), ZERO);
return ex.multiply(
new Complex(StrictMath.cos(z.imag()), StrictMath.sin(z.imag())));
}
/**
* Complex power
* @param z - the complex base
* @param y - the complex exponent
* @return
*/
public static Complex pow(Complex z, Complex y)
{
// if both Im(z) and Im(y) are zero, treat as double arithmetic
if (z.imag() == 0.0 || y.imag() == 0.0)
{
return new Complex(StrictMath.pow(z.real(),y.real()));
}
double c = y.real();
double d = y.imag();
// get polar of base
double r = Complex.abs(z);
double theta = Complex.arg(z);
Complex f1 = new Complex(
(StrictMath.pow(r, c)*StrictMath.pow(StrictMath.E, -d*theta)),ZERO);
Complex f2 =
new Complex(
StrictMath.cos(d*StrictMath.log(r)+c*theta),
StrictMath.sin(d*StrictMath.log(r)+c*theta));
return f1.multiply(f2);
}
/**
* Complex number raised to a real power
* @param z - the complex base
* @param a - the real exponent
* @return
*/
public static Complex pow(Complex z, double a)
{
// if Im(z) is zero, treat as double arithmetic
if (z.imag() == 0.0)
{
return new Complex(StrictMath.pow(z.real(),a));
}
// get polar of base
double r = Complex.abs(z);
double theta = Complex.arg(z);
// check n significant digits to see if rounding is required
if (functions.frac(r) > 0.9999001)
{
r = StrictMath.round(r);
}
double angle = theta*a;
double np = StrictMath.pow(r, a);
double Re = np*StrictMath.cos(angle);
if (functions.frac(Re) > 0.9999001)
{
Re = StrictMath.round(Re);
}
double Im = np*StrictMath.sin(angle);
if (functions.frac(Im) > 0.9999001)
{
Im = StrictMath.round(Im);
}
return new Complex(Re, Im);
}
/**
* Real number raised to a complex power
* @param a - the real base
* @param z - the complex exponent
* @return
*/
public static Complex pow(double a, Complex z)
{
double a2x = StrictMath.pow(a, z.real());
if (functions.frac(a2x) > 0.9999001)
{
a2x = StrictMath.round(a2x);
}
Complex ax = new Complex(a2x, ZERO);
Complex result =
new Complex(StrictMath.cos(z.imag()*StrictMath.log(a)),
StrictMath.sin(z.imag()*StrictMath.log(a)));
return ax.multiply(result);
}
/**
* find square root of complex number z
* @param z
* @return
*/
public static Complex sqrt(Complex z)
{
return sqrtn(z, 2);
}
/**
* Find nTh root of complex number
* @param z
* @param n
* @return
*/
public static Complex sqrtn(Complex z, int n)
{
// get polar of base
double r = Complex.abs(z);
// check n significant digits to see if rounding is required
if (functions.frac(r) > 0.9999001)
{
r = StrictMath.round(r);
}
double theta = Complex.arg(z);
// note: adding Pi to angle reverses signs
double angle = theta/n;
// get nTh root of r
double nrt = StrictMath.pow(r, 1./n);
double Re = nrt*StrictMath.cos(angle);
if (functions.frac(Re) > 0.9999001)
{
Re = StrictMath.round(Re);
}
double Im = nrt*StrictMath.sin(angle);
if (functions.frac(Im) > 0.9999001)
{
Im = StrictMath.round(Im);
}
return new Complex(
Re, Im);
}
/**
* Natural logarithm of a complex number
* @param complex number z
* @return
*/
public static Complex log(Complex z)
{
// get polar form
double r = Complex.abs(z);
double theta = Complex.arg(z);
return new Complex(StrictMath.log(r), theta);
}
/**
* Trigonometric functions - sine
* @param z
* @return
*/
public static Complex sin(Complex z)
{
// if Im(z) is zero, handle as double arithmetic
if (z.imag() == 0.0)
{
return new Complex(StrictMath.sin(z.real()));
}
return (exp(Complex.Iz(z))).subtract(exp(Complex.nIz(z)))
.divide(Complex.Iz(new Complex(2.)));
}
/**
* Trigonometric functions - cosine
* @param z
* @return
*/
public static Complex cos(Complex z)
{
// if Im(z) is zero, handle as double arithmetic
if (z.imag() == 0.0)
{
return new Complex(StrictMath.cos(z.real()));
}
return (exp(Complex.Iz(z))).add(exp(Complex.nIz(z)))
.divide(new Complex(2.,0.));
}
/**
* Trigonometric functions - secant
* @param z
* @return
*/
public static Complex sec(Complex z)
{
return one.divide(cos(z));
}
/**
* Trigonometric functions - cosecant
* @param z
* @return
*/
public static Complex csc(Complex z)
{
return one.divide(sin(z));
}
/**
* Trigonometric functions - tangent
* @param z
* @return
*/
public static Complex tan(Complex z)
{
return (sin(z)).divide(cos(z));
}
/**
* Trigonometric functions - cotangent
* @param z
* @return
*/
public static Complex cot(Complex z)
{
return (cos(z)).divide(sin(z));
}
/**
* Hyperbolic functions - sine
* @param z
* @return
*/
public static Complex sinh(Complex z)
{
return (exp(z)).subtract(exp(z.neg()))
.divide(new Complex(2.));
}
/**
* Hyperbolic functions - cosine
* @param z
* @return
*/
public static Complex cosh(Complex z)
{
return (exp(z)).add(exp(z.neg()))
.divide(new Complex(2.));
}
/**
* Hyperbolic functions - tangent
* @param z
* @return
*/
public static Complex tanh(Complex z)
{
return (sinh(z)).divide(cosh(z));
}
/**
* Hyperbolic functions - cotangent
* @param z
* @return
*/
public static Complex coth(Complex z)
{
return (cosh(z)).divide(sinh(z));
}
/**
* Hyperbolic functions - secant
* @param z
* @return
*/
public static Complex sech(Complex z)
{
return one.divide(cosh(z));
}
/**
* Hyperbolic functions - cosecant
* @param z
* @return
*/
public static Complex csch(Complex z)
{
return one.divide(sinh(z));
}
/**
* Inverse trigonometric functions - arcsin
* implemented using log form
* @param z
* @return
*/
public static Complex asin(Complex z)
{
Complex result =
nI.multiply(
log(Complex.Iz(z)
.add(sqrt(new Complex(1.).subtract(pow(z,2.))))));
return result;
}
/**
* Inverse trigonometric functions - arcosine
* implemented using log form
* @param z
* @return
*/
public static Complex acos(Complex z)
{
Complex result =
nI.multiply(
log(z.add(sqrt(pow(z,2.).subtract(one)))));
double re = result.real();
double im = result.imag();
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(re),im);
}
return result;
}
/**
* Inverse trigonometric functions - arctangent
* implemented using log form
* @param z
* @return
*/
public static Complex atan(Complex z)
{
Complex iz = Complex.Iz(z);
Complex result =
new Complex(0.,-.5)
.multiply(log(one.add(iz).divide(one.subtract(iz))));
double re = result.real();
double im = result.imag();
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(re),im);
}
return result;
}
/**
* Inverse trigonometric functions - arccosecant
* implemented using log form
* @param z
* @return
*/
public static Complex acsc(Complex z)
{
Complex result =
new Complex(0.,-.1)
.multiply(log(I.add(sqrt(pow(z,2.))).divide(z)));
double re = result.real();
double im = result.imag();
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(re),im);
}
return result;
}
/**
* Inverse trigonometric functions - arcsecant
* implemented using log form
* @param z
* @return
*/
public static Complex asec(Complex z)
{
Complex result =
new Complex(0.,-.1)
.multiply(log(one.add(sqrt(one.subtract(pow(z,2.))).divide(z))));
double re = result.real();
double im = result.imag();
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(re),im);
}
return result;
}
/**
* Inverse trigonometric functions - arccotangent
* implemented using log form
* @param z
* @return
*/
public static Complex acot(Complex z)
{
Complex result =
new Complex(0.,-.5)
.multiply(log(z.add(I).divide(z.subtract(I))));
double re = result.real();
double im = result.imag();
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(re),im);
}
return result;
}
/**
* Inverse hyperbolic functions - arcsine
* implemented using log form
* @param z
* @return
*/
public static Complex asinh(Complex z)
{
Complex result = log(z.add(sqrt(pow(z,2.).add(one))));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* Inverse hyperbolic functions - arcosine
* implemented using log form
* @param z
* @return
*/
public static Complex acosh(Complex z)
{
Complex result = log(z.add(sqrt(pow(z,2.).subtract(one))));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* Inverse hyperbolic functions - arctangent
* implemented using log form
* @param z
* @return
*/
public static Complex atanh(Complex z)
{
Complex result =
new Complex(.5).multiply(log(one.add(z).divide(one.subtract(z))));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* Inverse hyperbolic functions - arcosecant
* implemented using log form
* @param z
* @return
*/
public static Complex acsch(Complex z)
{
Complex result =
log(one.add(sqrt(pow(z,2.).add(one))).divide(z));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* Inverse hyperbolic functions - arcsecant
* implemented using log form
* @param z
* @return
*/
public static Complex asech(Complex z)
{
Complex result =
log(one.add(sqrt(one.subtract(pow(z,2.))).divide(z)));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* Inverse hyperbolic functions - arccotangent
* implemented using log form
* @param z
* @return
*/
public static Complex acoth(Complex z)
{
Complex result =
new Complex(.5).multiply(
log(z.add(one).divide(z.subtract(one))));
double re = result.real();
// strip the sign for the rounding test
if (re < 0.0)
{
re *= -1.;
}
// rounding check
if (functions.frac(re) > 0.9999001)
{
result = new Complex(StrictMath.round(result.real()),result.imag());
}
return result;
}
/**
* extended Gamma function for complex arguments
* @param s
* @return
*/
public static Complex PI(Complex s)
{
int n = 1;
Complex result = (pow((double)n, one.subtract(s))
.multiply(pow((double)n+1, s)))
.divide(s.add(one));
for (n=2;n<INFINITY;n++)
{
result = result.multiply((pow((double)n, one.subtract(s))
.multiply(pow((double)n+1, s)))
.divide(s.add(new Complex((double)n))));
}
return result;
}
public static void main(String[] args)
{
// all tests moved to JUnit test case
}
}
@pbarama
Copy link

pbarama commented Aug 9, 2020

Where this will be used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment