Complex.java
/*
* Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.irurueta.algebra;
import java.io.Serializable;
import java.util.Objects;
/**
* Class defining a Complex number having real and imaginary parts.
*/
public class Complex implements Serializable, Cloneable {
/**
* Real part of the complex number.
*/
private double real;
/**
* Imaginary part of the complex number.
*/
private double imaginary;
/**
* Constructor. Sets both real and imaginary parts to zero.
*/
public Complex() {
real = imaginary = 0.0;
}
/**
* Creates new Complex number having provided real value and an
* imaginary part equal to zero.
*
* @param real Real part.
*/
public Complex(final double real) {
this.real = real;
imaginary = 0.0;
}
/**
* Creates new Complex number having provided real and imaginary parts.
*
* @param real Real part.
* @param imaginary Imaginary part.
*/
public Complex(final double real, final double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
/**
* Creates new Complex number by copying provided value.
*
* @param initValue Initial value to be copied.
*/
public Complex(final Complex initValue) {
this.real = initValue.real;
this.imaginary = initValue.imaginary;
}
/**
* Returns real part of complex number.
*
* @return Real part.
*/
public double getReal() {
return real;
}
/**
* Sets real part of complex number.
*
* @param real Real part.
*/
public void setReal(final double real) {
this.real = real;
}
/**
* Returns imaginary part of complex number.
*
* @return Imaginary part.
*/
public double getImaginary() {
return imaginary;
}
/**
* Sets imaginary part of complex number.
*
* @param imaginary Imaginary part.
*/
public void setImaginary(final double imaginary) {
this.imaginary = imaginary;
}
/**
* Sets both real and imaginary parts of this complex number.
*
* @param real Real part.
* @param imaginary Imaginary part.
*/
public void setRealAndImaginary(final double real, final double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
/**
* Returns modulus of current complex number, which is equal to the
* length of the vector formed by the real and imaginary parts.
*
* @return Modulus.
*/
public double getModulus() {
return Math.sqrt(real * real + imaginary * imaginary);
}
/**
* Returns phase of current complex number, in radians.
* Phase is equal to the angle of the vector formed by the real and
* imaginary parts.
*
* @return Phase in radians.
*/
public double getPhase() {
return Math.atan2(imaginary, real);
}
/**
* Sets both modulus and phase of this complex number.
*
* @param modulus Modulus to be set.
* @param phase Phase to be set in radians.
*/
public void setModulusAndPhase(final double modulus, final double phase) {
real = modulus * Math.cos(phase);
imaginary = modulus * Math.sin(phase);
}
/**
* Computes the complex conjugate of this instance and stores the
* result into provided complex instance.
* The complex conjugate is obtained by negating the sign of the
* imaginary part.
*
* @param result Complex instance where conjugate is stored.
*/
public void conjugate(final Complex result) {
result.real = real;
result.imaginary = -imaginary;
}
/**
* Computes the complex conjugate of this instance and returns the
* result as a new instance.
*
* @return Complex conjugate.
*/
public Complex conjugateAndReturnNew() {
final var result = new Complex();
conjugate(result);
return result;
}
/**
* Changes this instance into its complex conjugate.
*/
public void conjugate() {
conjugate(this);
}
/**
* Adds this instance with provided complex value and stores the result
* in provided instance
*
* @param other Complex to be added to current instance.
* @param result Complex instance where result is stored.
*/
public void add(final Complex other, final Complex result) {
result.real = real + other.real;
result.imaginary = imaginary + other.imaginary;
}
/**
* Adds this instance to provided complex and returns the result as a new
* instance.
*
* @param other Complex to be added to current instance.
* @return Result of summation.
*/
public Complex addAndReturnNew(final Complex other) {
final var result = new Complex();
add(other, result);
return result;
}
/**
* Adds provided complex into this instance
*
* @param other Complex to be added to current instance.
*/
public void add(final Complex other) {
add(other, this);
}
/**
* Subtracts provided instance from this instance and stores the result
* in provided instance.
*
* @param other Complex to be subtracted from this instance.
* @param result Complex instance where result is stored.
*/
public void subtract(final Complex other, final Complex result) {
result.real = real - other.real;
result.imaginary = imaginary - other.imaginary;
}
/**
* Subtracts provided instance from this instance and returns the result
* as a new instance
*
* @param other Complex to be subtracted from current instance.
* @return Result of subtraction.
*/
public Complex subtractAndReturnNew(final Complex other) {
final var result = new Complex();
subtract(other, result);
return result;
}
/**
* Subtracts provided complex from this instance.
*
* @param other Complex to be subtracted from current instance.
*/
public void subtract(final Complex other) {
subtract(other, this);
}
/**
* Multiplies this instance with provided instance and stores the result
* in provided instance.
*
* @param other Complex to be multiplied to this instance
* @param result Complex instance where result is stored.
*/
public void multiply(final Complex other, final Complex result) {
final var tmpReal = (real * other.real) - (imaginary * other.imaginary);
final var tmpImaginary = (imaginary * other.real) + (real * other.imaginary);
result.real = tmpReal;
result.imaginary = tmpImaginary;
}
/**
* Multiplies provided instance with this instance and returns the result
* as a new instance.
*
* @param other Complex to be multiplied to current instance.
* @return Result of multiplication.
*/
public Complex multiplyAndReturnNew(final Complex other) {
final var result = new Complex();
multiply(other, result);
return result;
}
/**
* Multiplies provided complex with this instance.
*
* @param other Complex to be multiplied to this instance.
*/
public void multiply(final Complex other) {
multiply(other, this);
}
/**
* Divides this instance by provided instance and stores the result in
* provided instance.
*
* @param other Complex to divide this instance by.
* @param result Complex instance where result is stored.
*/
public void divide(final Complex other, final Complex result) {
final var tmpReal = ((real * other.real) + (imaginary * other.imaginary))
/ ((other.real * other.real) + (other.imaginary * other.imaginary));
final var tmpImaginary = ((imaginary * other.real) - (real * other.imaginary))
/ ((other.real * other.real) + (other.imaginary * other.imaginary));
result.real = tmpReal;
result.imaginary = tmpImaginary;
}
/**
* Divides this instance by provided instance and returns the result as
* a new instance.
*
* @param other Complex to divide this instance by.
* @return Result of division.
*/
public Complex divideAndReturnNew(final Complex other) {
final var result = new Complex();
divide(other, result);
return result;
}
/**
* Divides this instance by provided complex.
*
* @param other Complex to divide this instance by.
*/
public void divide(final Complex other) {
divide(other, this);
}
/**
* Multiplies this instance by provided scalar value (multiplying both
* real and imaginary parts by provided value) and stores the result in
* provided complex instance.
*
* @param scalar Value to multiply this instance by.
* @param result Complex where result of multiplication is stored.
*/
public void multiplyByScalar(final double scalar, final Complex result) {
result.real = scalar * real;
result.imaginary = scalar * imaginary;
}
/**
* Multiplies this instance by provided scalar value (multiplying both
* real and imaginary parts by provided value) and returns the result
* as a new instance.
*
* @param scalar Value to multiply this instance by.
* @return Result of multiplication by scalar.
*/
public Complex multiplyByScalarAndReturnNew(final double scalar) {
final var result = new Complex();
multiplyByScalar(scalar, result);
return result;
}
/**
* Multiplies this instance by provided scalar
*
* @param scalar Value to multiply this instance by.
*/
public void multiplyByScalar(final double scalar) {
multiplyByScalar(scalar, this);
}
/**
* Computes the power of this instance by provided exponent and stores
* the result in provided instance.
*
* @param exponent Exponent to power this instance by.
* @param result Complex where the power is stored.
*/
public void pow(final double exponent, final Complex result) {
result.setModulusAndPhase(Math.pow(getModulus(), exponent), getPhase() * exponent);
}
/**
* Computes the power of this instance by provided exponent and returns
* the result as a new instance.
*
* @param exponent Exponent to power this instance by.
* @return Complex where the power is stored.
*/
public Complex powAndReturnNew(final double exponent) {
final var result = new Complex();
pow(exponent, result);
return result;
}
/**
* Computes the power of this instance by provided exponent
*
* @param exponent Exponent to power this instance by.
*/
public void pow(final double exponent) {
pow(exponent, this);
}
/**
* Computes the squared root of this instance and returns the result as
* a new instance.
*
* @param result Complex where squared root is stored.
*/
public void sqrt(final Complex result) {
pow(0.5, result);
}
/**
* Computes the squared root of this instance and returns the result as a
* new instance.
*
* @return Squared root of this instance.
*/
public Complex sqrtAndReturnNew() {
final var result = new Complex();
sqrt(result);
return result;
}
/**
* Computes the squared root of this instance
*/
public void sqrt() {
sqrt(this);
}
/**
* Determines whether two Complex objects are equal or not.
* Two Complex are considered to be equal if both their real and imaginary
* parts are equal.
*
* @param obj Object to compare.
* @return True if both Complex objects are equal.
*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Complex other)) {
return false;
}
return equals(other, 0.0);
}
/**
* Computes the hashcode of this instance.
*
* @return Hashcode
*/
@Override
public int hashCode() {
return Objects.hash(real, imaginary);
}
/**
* Determines whether two Complex objects are equal or not up to a certain
* level of tolerance in both their real and imaginary parts. When the
* difference in both their real and imaginary parts is below the tolerance
* level, then both instances are considered to be equal.
*
* @param other Other Complex to compare.
* @param tolerance Margin of tolerance.
* @return Returns true if both Complex instances are considered to be
* equal.
*/
public boolean equals(final Complex other, final double tolerance) {
if (Math.abs(real - other.real) > tolerance) {
return false;
}
return Math.abs(imaginary - other.imaginary) <= tolerance;
}
/**
* Makes a copy of this instance having the same real and imaginary parts.
*
* @return a copy of this instance.
* @throws CloneNotSupportedException if clone fails.
*/
@Override
public Complex clone() throws CloneNotSupportedException {
final var result = (Complex) super.clone();
result.setRealAndImaginary(real, imaginary);
return result;
}
/**
* Copies provided value into current instance.
*
* @param value Value to copy from.
*/
public void copyFrom(final Complex value) {
this.real = value.real;
this.imaginary = value.imaginary;
}
}