package jscl.math.numeric; import jscl.AngleUnit; import jscl.JsclMathEngine; import jscl.math.NotDivisibleException; import jscl.math.NotDoubleException; import jscl.text.msg.JsclMessage; import jscl.text.msg.Messages; import org.solovyev.common.msg.MessageType; import javax.annotation.Nonnull; public final class Complex extends Numeric { @Nonnull public static final Complex I = new Complex(0, 1); private final double real, imaginary; private Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } @Nonnull public static Complex valueOf(double real, double imaginary) { if (JsclMathEngine.getInstance().getAngleUnits() != AngleUnit.rad) { JsclMathEngine.getInstance().getMessageRegistry().addMessage(new JsclMessage(Messages.msg_23, MessageType.warning)); } if (real == 0d && imaginary == 1d) { return I; } else { return new Complex(real, imaginary); } } public Complex add(Complex complex) { return valueOf(real + complex.real, imaginary + complex.imaginary); } @Nonnull public Numeric add(@Nonnull Numeric that) { if (that instanceof Complex) { return add((Complex) that); } else if (that instanceof Real) { return add(valueOf(that)); } else { return that.valueOf(this).add(that); } } public Complex subtract(Complex complex) { return valueOf(real - complex.real, imaginary - complex.imaginary); } @Nonnull public Numeric subtract(@Nonnull Numeric that) { if (that instanceof Complex) { return subtract((Complex) that); } else if (that instanceof Real) { return subtract(valueOf(that)); } else { return that.valueOf(this).subtract(that); } } public Complex multiply(Complex complex) { return valueOf(real * complex.real - imaginary * complex.imaginary, real * complex.imaginary + imaginary * complex.real); } @Nonnull public Numeric multiply(@Nonnull Numeric that) { if (that instanceof Complex) { return multiply((Complex) that); } else if (that instanceof Real) { return multiply(valueOf(that)); } else { return that.multiply(this); } } public Complex divide(Complex complex) throws ArithmeticException { return multiply((Complex) complex.inverse()); } @Nonnull public Numeric divide(@Nonnull Numeric that) throws NotDivisibleException { if (that instanceof Complex) { return divide((Complex) that); } else if (that instanceof Real) { return divide(valueOf(that)); } else { return that.valueOf(this).divide(that); } } @Nonnull public Numeric negate() { return valueOf(-real, -imaginary); } @Nonnull @Override public Numeric abs() { final Numeric realSquare = new Real(real).pow(2); final Numeric imaginarySquare = new Real(imaginary).pow(2); final Numeric sum = realSquare.add(imaginarySquare); return sum.sqrt(); } public int signum() { int result; if (real > .0) { result = 1; } else if (real < .0) { result = -1; } else { result = Real.signum(imaginary); } return result; } public double magnitude() { return Math.sqrt(real * real + imaginary * imaginary); } public double magnitude2() { return real * real + imaginary * imaginary; } public double angle() { return Math.atan2(imaginary, real); } @Nonnull public Numeric ln() { if (signum() == 0) { return Real.ZERO.ln(); } else { return valueOf(Math.log(magnitude()), angle()); } } @Nonnull public Numeric lg() { if (signum() == 0) { return Real.ZERO.lg(); } else { return valueOf(Math.log10(magnitude()), angle()); } } @Nonnull public Numeric exp() { return valueOf(Math.cos(defaultToRad(imaginary)), Math.sin(defaultToRad(imaginary))).multiply(Math.exp(real)); } @Nonnull public Numeric inverse() { return ((Complex) conjugate()).divide(magnitude2()); } Complex multiply(double d) { return valueOf(real * d, imaginary * d); } Complex divide(double d) { return valueOf(real / d, imaginary / d); } public Numeric conjugate() { return valueOf(real, -imaginary); } public double realPart() { return real; } public double imaginaryPart() { return imaginary; } public int compareTo(Complex that) { if (imaginary < that.imaginary) { return -1; } else if (imaginary > that.imaginary) { return 1; } else if (imaginary == that.imaginary) { if (real < that.real) { return -1; } else if (real > that.real) { return 1; } else if (real == that.real) { return 0; } else throw new ArithmeticException(); } else throw new ArithmeticException(); } public int compareTo(Numeric that) { if (that instanceof Complex) { return compareTo((Complex) that); } else if (that instanceof Real) { return compareTo(valueOf(that)); } else { return that.valueOf(this).compareTo(that); } } @Override public double doubleValue() { throw NotDoubleException.get(); } public Complex copyOf(@Nonnull Complex complex) { return valueOf(complex.real, complex.imaginary); } @Nonnull public Numeric valueOf(@Nonnull Numeric numeric) { if (numeric instanceof Complex) { return copyOf((Complex) numeric); } else if (numeric instanceof Real) { Real d = (Real) numeric; return d.toComplex(); } else throw new ArithmeticException(); } public String toString() { final StringBuilder result = new StringBuilder(); if (imaginary == 0.) { result.append(toString(real)); } else { if (real != 0.) { result.append(toString(real)); if (imaginary > 0.) { result.append("+"); } } if (imaginary != 1.) { if (imaginary == -1.) { result.append("-"); } else { if (imaginary < 0.) { final String imagStr = toString(imaginary); // due to rounding we can forget sign (-0.00000000001 can be round to 0 => plus sign would not be added above and no sign will be before i) if (imagStr.startsWith("-")) { result.append(imagStr); } else { result.append("-").append(imagStr); } } else { result.append(toString(imaginary)); } result.append("*"); } } result.append("i"); } return result.toString(); } }