us.ihmc.math.ComplexNumber Maven / Gradle / Ivy
package us.ihmc.math;
import us.ihmc.commons.MathTools;
import us.ihmc.euclid.interfaces.Settable;
import us.ihmc.euclid.tools.EuclidCoreTools;
import java.util.List;
/**
* {@link ComplexNumber} implements a complex number and defines complex
* arithmetic and mathematical functions. A complex number is a combination of a real and unreal number
*
* z = u + i * v
*
*/
public class ComplexNumber implements Settable
{
private static final double TAU = Math.PI * 2.0;
private double real, imaginary;
/**
* Constructs the complex number with zero value.
*/
public ComplexNumber()
{
setToZero();
}
/**
* Constructs the complex number z = u + i*v
*
* @param real Real part (u in above equation)
* @param imaginary imag part (v in above equation)
*/
public ComplexNumber(double real, double imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
/**
* Constructs this complex number, and sets its value to be equivalent to {@code complexNumber}.
*
* @param complexNumber value to set this number to
*/
public ComplexNumber(ComplexNumber complexNumber)
{
this(complexNumber.real, complexNumber.imaginary);
}
/**
* Sets this complex number real and imaginary values.
*
* @param real desired real value
* @param imaginary desired imaginary value
*/
public void set(double real, double imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
/**
* Sets this complex number real and imaginary value to equal the other number.
*
* @param other desired complex number to copy
*/
@Override
public void set(ComplexNumber other)
{
set(other.real, other.imaginary);
}
/**
* Sets the real value of this complex number.
* (the x-coordinate in rectangular coordinates).
*
* @param real desired real value
*/
public void setReal(double real)
{
this.real = real;
}
/**
* Sets the imaginary value of this complex number
* (the y-coordinate in rectangular coordinates).
*
* @param imaginary desired imaginary value
*/
public void setImaginary(double imaginary)
{
this.imaginary = imaginary;
}
/**
* Sets the complex number to only a real number, setting the imaginary value to zero.
* (the x-coordinate in rectangular coordinates with no y-coordinate).
*
* @param real desired real value.
*/
public void setToPurelyReal(double real)
{
this.real = real;
this.imaginary = 0;
}
/**
* Sets the complex number values from its polar coordinates
*
* @param magnitude magnitude in polar coordinates
* @param angle angle (radians) in polar coordinates
*/
public void setFromPolar(double magnitude, double angle)
{
this.real = magnitude * Math.cos(angle);
this.imaginary = magnitude * Math.sin(angle);
}
/**
* Sets the real and imaginary values to zero, setting this complex number to the origin.
*/
public void setToZero()
{
this.real = 0.0;
this.imaginary = 0.0;
}
/**
* Real part of this Complex number
* (the x-coordinate in rectangular coordinates).
*
* @return Re[z] where z is this Complex number.
*/
public double real()
{
return real;
}
/**
* imag part of this Complex number
* (the y-coordinate in rectangular coordinates).
*
* @return Im[z] where z is this Complex number.
*/
public double imaginary()
{
return imaginary;
}
/**
* Modulus of this Complex number
* (the distance from the origin in polar coordinates).
*
* @return |z| where z is this Complex number.
*/
public double magnitude()
{
if (real == 0.0)
{
return imaginary;
}
else if (imaginary == 0.0)
{
return real;
}
else
{
return EuclidCoreTools.norm(real, imaginary);
}
}
/**
* Squared value of the modulus of this Complex number
* (the distance from the origin in polar coordinates).
*
* @return |z|^2 where z is this Complex number.
*/
public double magnitudeSquared()
{
if (real == 0.0)
{
return imaginary;
}
else if (imaginary == 0.0)
{
return real;
}
else
{
return EuclidCoreTools.normSquared(real, imaginary);
}
}
/**
* Argument of this Complex number
* (the angle in radians with the x-axis in polar coordinates).
*
* @return arg(z) where z is this Complex number.
*/
public double angle()
{
return Math.atan2(imaginary, real);
}
/**
* Complex conjugate of this Complex number
* (the conjugate of x+i*y is x-i*y).
*
* @return z-bar where z is this Complex number.
*/
public ComplexNumber conjugate()
{
return new ComplexNumber(real, -imaginary);
}
/**
* Addition of ComplexNumbers (doesn't change this ComplexNumber).
*
(x+i*y) + (s+i*t) = (x+s)+i*(y+t).
*
* WARNING: this generates garbage
*
*
* @param w is the number to add.
* @return z + w, where z is this ComplexNumber.
*/
public ComplexNumber plus(ComplexNumber w)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.addEquals(w);
return complexNumber;
}
/**
* Addition of ComplexNumbers
*
this = z1 + z2.
*
* @param z1 is the first number to add. Not modified.
* @param z2 is the second number to add. Not modified.
*/
public void add(ComplexNumber z1, ComplexNumber z2)
{
set(z1.real() + z2.real(), z1.imaginary() + z2.imaginary());
}
/**
* Addition of ComplexNumbers to this value, stored here.
*
this += other.
*
* @param other complex number to add. Not modified.
*/
public void addEquals(ComplexNumber other)
{
addEquals(other.real(), other.imaginary());
}
/**
* Addition of ComplexNumbers to this value, stored here.
*
this += other.
*
* @param real real value of complex number to add.
* @param imaginary real value of complex number to add.
*/
public void addEquals(double real, double imaginary)
{
this.real += real;
this.imaginary += imaginary;
}
/**
* Addition of real only ComplexNumbers (doesn't change this ComplexNumber).
*
(x+i*y) + d = (x+d)+i*y.
*
* WARNING: this generates garbage
*
*
* @param d real value to add to this complex number.
* @return z + w, where z is this ComplexNumber.
*/
public ComplexNumber plus(double d)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.addEquals(d, 0.0);
return complexNumber;
}
/**
* Addition of ComplexNumbers (doesn't change this ComplexNumber).
*
(x+i*y) - (s+i*t) = (x-s)+i*(y-t).
*
* WARNING: this generates garbage
*
*
* @param w is the number to subtract.
* @return z + w, where z is this ComplexNumber.
*/
public ComplexNumber minus(ComplexNumber w)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.minusEquals(w);
return complexNumber;
}
/**
* Subtraction of real only ComplexNumbers (doesn't change this ComplexNumber).
*
(x+i*y) - d = (x-d)+i*y.
*
* WARNING: this generates garbage
*
*
* @param d real value to subtract to this complex number.
* @return z + w, where z is this ComplexNumber.
*/
public ComplexNumber minus(double d)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.minusEquals(d, 0.0);
return complexNumber;
}
/**
* Subtraction of ComplexNumbers, stored here.
*
this = c1 - c2.
*
* @param c1 complex number to subtract from. Not modified.
* @param c2 complex number to subtract. Not modified.
*/
public void minus(ComplexNumber c1, ComplexNumber c2)
{
set(c1.real() - c2.real(), c1.imaginary() - c2.imaginary());
}
/**
* Subtraction of ComplexNumbers from this value, stored here.
*
this -= other.
*
* @param other complex number to subtract. Not modified.
*/
public void minusEquals(ComplexNumber other)
{
minusEquals(other.real, other.imaginary);
}
/**
* Subtraction of ComplexNumbers from this value, stored here.
*
this -= other.
*
* @param real real value of complex number to subtract.
* @param imaginary imaginary value of complex number to subtract.
*/
public void minusEquals(double real, double imaginary)
{
this.real -= real;
this.imaginary -= imaginary;
}
/**
* ComplexNumber multiplication (doesn't change this ComplexNumber).
*
* @param w is the number to multiply by.
* @return z*w where z is this ComplexNumber.
*/
public ComplexNumber times(ComplexNumber w)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.timesEquals(w);
return complexNumber;
}
/**
* ComplexNumber multiplication by a real number (doesn't change this ComplexNumber).
*
* @param w is the number to multiply by.
* @return z*w where z is this ComplexNumber.
*/
public ComplexNumber times(double w)
{
ComplexNumber complexNumber = new ComplexNumber(this);
complexNumber.timesEquals(w, 0.0);
return complexNumber;
}
/**
* ComplexNumber multiplication, and stores here.
* this *= other
*
* @param other is the number to multiply by. Not modified.
*/
public void timesEquals(ComplexNumber other)
{
this.timesEquals(other.real, other.imaginary);
}
/**
* ComplexNumber multiplication, and stores here.
* this *= other
*
* @param real is the real value to multiply by.
* @param imaginary is the real value to multiply by.
*/
public void timesEquals(double real, double imaginary)
{
double tempVal1 = this.real * real - this.imaginary * imaginary;
this.imaginary = this.real * imaginary + real * this.imaginary;
this.real = tempVal1;
}
/**
* ComplexNumber multiplication, storing here.
* this = c1 * c2.
*
* @param c1 left side of the multiplication. Not modified.
* @param c2 right side of the multiplication. Not modified.
*/
public void times(ComplexNumber c1, ComplexNumber c2)
{
set(c1);
timesEquals(c2);
}
/**
* Division of ComplexNumbers (doesn't change this ComplexNumber).
*
(x+i*y)/(s+i*t) = ((x*s+y*t) + i*(y*s-y*t)) / (s^2+t^2)
*
* @param w is the number to divide by
* @return new ComplexNumber z/w where z is this ComplexNumber
*/
public ComplexNumber dividedBy(ComplexNumber w)
{
double den = MathTools.square(w.magnitude());
return new ComplexNumber((real * w.real() + imaginary * w.imaginary()) / den, (imaginary * w.real() - real * w.imaginary()) / den);
}
/**
* Scales the magnitude of this complex number, while maintaining the direction
* this *= scalar.
*
* @param scalar amount to scael the magnitude.
*/
public void scale(double scalar)
{
this.real *= scalar;
this.imaginary *= scalar;
}
/**
* ComplexNumber exponential (doesn't change this ComplexNumber).
*
* @return exp(z) where z is this ComplexNumber.
*/
public ComplexNumber exp()
{
return new ComplexNumber(Math.exp(real) * Math.cos(imaginary), Math.exp(real) * Math.sin(imaginary));
}
/**
* Principal branch of the ComplexNumber logarithm of this ComplexNumber.
* (doesn't change this ComplexNumber).
* The principal branch is the branch with -pi < arg <= pi.
*
* @return log(z) where z is this ComplexNumber.
*/
public ComplexNumber log()
{
return new ComplexNumber(Math.log(this.magnitude()), this.angle());
}
/**
* ComplexNumber square root (doesn't change this ComplexNumber).
* Computes the principal branch of the square root, which
* is the value with 0 <= arg < pi.
*
* @return sqrt(z) where z is this ComplexNumber.
*/
public ComplexNumber sqrt()
{
double r = Math.sqrt(this.magnitude());
double theta = this.angle() / 2;
return new ComplexNumber(r * Math.cos(theta), r * Math.sin(theta));
}
// Real cosh function (used to compute ComplexNumber trig functions)
private double cosh(double theta)
{
return (Math.exp(theta) + Math.exp(-theta)) / 2;
}
// Real sinh function (used to compute ComplexNumber trig functions)
private double sinh(double theta)
{
return (Math.exp(theta) - Math.exp(-theta)) / 2;
}
/**
* Sine of this ComplexNumber (doesn't change this ComplexNumber).
*
sin(z) = (exp(i*z)-exp(-i*z))/(2*i).
*
* @return sin(z) where z is this ComplexNumber.
*/
public ComplexNumber sin()
{
return new ComplexNumber(cosh(imaginary) * Math.sin(real), sinh(imaginary) * Math.cos(real));
}
/**
* Cosine of this ComplexNumber (doesn't change this ComplexNumber).
*
cos(z) = (exp(i*z)+exp(-i*z))/ 2.
*
* @return cos(z) where z is this ComplexNumber.
*/
public ComplexNumber cos()
{
return new ComplexNumber(cosh(imaginary) * Math.cos(real), -sinh(imaginary) * Math.sin(real));
}
/**
* Hyperbolic sine of this ComplexNumber
* (doesn't change this ComplexNumber).
*
sinh(z) = (exp(z)-exp(-z))/2.
*
* @return sinh(z) where z is this ComplexNumber.
*/
public ComplexNumber sinh()
{
return new ComplexNumber(sinh(real) * Math.cos(imaginary), cosh(real) * Math.sin(imaginary));
}
/**
* Hyperbolic cosine of this ComplexNumber
* (doesn't change this ComplexNumber).
*
cosh(z) = (exp(z) + exp(-z)) / 2.
*
* @return cosh(z) where z is this ComplexNumber.
*/
public ComplexNumber cosh()
{
return new ComplexNumber(cosh(real) * Math.cos(imaginary), sinh(real) * Math.sin(imaginary));
}
/**
* Tangent of this ComplexNumber (doesn't change this ComplexNumber).
*
tan(z) = sin(z)/cos(z).
*
* @return tan(z) where z is this ComplexNumber.
*/
public ComplexNumber tan()
{
return (this.sin()).dividedBy(this.cos());
}
/**
* Negative of this ComplexNumber (chs stands for change sign).
* This produces a new ComplexNumber and doesn't change
* this ComplexNumber.
*
-(x+i*y) = -x-i*y.
*
* @return -z where z is this ComplexNumber.
*/
public ComplexNumber changeSign()
{
return new ComplexNumber(-real, -imaginary);
}
public boolean epsilonEquals(double realNumber, double epsilon)
{
if (Math.abs(this.real - realNumber) > epsilon)
return false;
if (Math.abs(this.imaginary) > epsilon)
return false;
return true;
}
public boolean epsilonEquals(ComplexNumber complexNumber, double epsilon)
{
if (Math.abs(this.real - complexNumber.real()) > epsilon)
return false;
if (Math.abs(this.imaginary - complexNumber.imaginary()) > epsilon)
return false;
return true;
}
public void getRoots(ComplexNumber root1, ComplexNumber root2)
{
double tempVal1 = Math.sqrt(magnitude());
double tempVal2 = angle();
root1.setFromPolar(tempVal1, tempVal2 / 2.0);
root2.setFromPolar(tempVal1, (tempVal2 + 2.0 * Math.PI) / 2.0);
}
public void getRoots(List rootsToPack, int n)
{
double tempVal1 = Math.pow(magnitude(), 1.0 / n);
double tempVal2 = angle() / n;
for (int i = 0; i < n; i++)
rootsToPack.get(i).setFromPolar(tempVal1, tempVal2 + (TAU * i) / (double) n);
}
/**
* String representation of this ComplexNumber.
*
* @return x+i*y, x-i*y, x, or i*y as appropriate.
*/
public String toString()
{
if ((real != 0) && (imaginary > 0))
{
return real + " + " + imaginary + "i";
}
if ((real != 0) && (imaginary < 0))
{
return real + " - " + (-imaginary) + "i";
}
if (imaginary == 0)
{
return String.valueOf(real);
}
if (real == 0)
{
return imaginary + "i";
}
// shouldn't get here (unless Inf or NaN)
return real + " + i*" + imaginary;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy