Java实现Complex复数类及其常见数学计算

Complex

  • 数学计算:加减乘除、求模、辐角、平方根、倒数、相反数、共轭复数等
  • 其他:字符串转复数parseComplex()、复数转字符串toString()
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A complex value with double precision.
 *
 * @author Cloudy1225
 */
public class Complex {

    private double real, imag;

    /***** Constant Variables *****/

    public static final Complex REAL_UNIT = new Complex(1.0, 0.0);
    public static final Complex NEG_REAL_UNIT = new Complex(-1.0, 0.0);
    public static final Complex IMAG_UNIT = new Complex(0.0, 1.0);
    public static final Complex NEG_IMAG_UNIT = new Complex(0.0, -1.0);
    public static final Complex ZERO = new Complex(0.0);

    /***** Constructors *****/

    public Complex(double real, double imag) {
        this.real = real;
        this.imag = imag;
    }

    public Complex(double real) {
        this.real = real;
        this.imag = 0;
    }

    public Complex() {
        this.real = 0;
        this.imag = 0;
    }

    /***** getter and setter *****/

    public double real() {
        return this.real;
    }

    public double imag() {
        return this.imag;
    }

    protected void set(double real, double imag) {
        this.real = real;
        this.imag = imag;
    }

    protected void setReal(double real) {
        this.real = real;
    }

    protected void setImag(double imag) {
        this.imag = imag;
    }

    /***** Override some methods in Object *****/

    @Override
    public String toString() {
        if (this.imag > 0) {
            return ((real==0) ? "" : real+"+") + imag + "i";
        } else if (this.imag < 0) {
            return ((real==0) ? "" : real+"") + imag + "i";
        } else {
            return String.valueOf(real);
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Complex)) return false;
        Complex other = (Complex) obj;
        return this.real == other.real && this.imag == other.imag;
    }

    @Override
    public int hashCode() {
        return Double.valueOf(this.real).hashCode() ^ Double.valueOf(this.imag).hashCode();
    }

    /**
     * Create a deep copy of the complex
     *
     * @return deep copy of the complex
     */
    public Complex copy() {
        return new Complex(this.real, this.imag);
    }

    /**
     * Constructs a newly allocated Complex object that
     * represents the complex value represented by the double.
     *
     * @param  d  a double to be converted to a complex.
     */
    public static Complex valueOf(double d) {
        return new Complex(d);
    }

    /**
     * Constructs a newly allocated Complex object that
     * represents the complex value represented by the string.
     *
     * @param  s  a string to be converted to a complex.
     * @throws    NumberFormatException  if the string does not contain a
     *            parsable number.
     */
    public static Complex valueOf(String s) {
        return parseComplex(s);
    }

    /**
     * Constructs a newly allocated Complex object that
     * represents the complex value represented by the string.
     *
     * @param  s  a string to be converted to a complex.
     * @throws    NumberFormatException  if the string does not contain a
     *            parsable number.
     */
    public static Complex parseComplex(String s) {
        double real = 0;
        double imag = 0;

        final String doubleRegex = "[-+]?(\\d+(\\.\\d*)?|\\.\\d+)([eE]([-+]?([012]?\\d{1,2}|30[0-7])|-3([01]?[4-9]|[012]?[0-3])))?";
        final String pureImagRegex = doubleRegex+"[a-zA-Z]";
        final String complexRegex1 = "(?"+doubleRegex+")" + "(?"+doubleRegex+")" + "[a-zA-Z]";
        final String complexRegex2 = "(?"+doubleRegex+")" + "[a-zA-Z]" + "(?"+doubleRegex+")";

        if (Pattern.compile(doubleRegex).matcher(s).matches()) { // It's just a real number.
            real = Double.parseDouble(s);
        } else if (Pattern.compile(pureImagRegex).matcher(s).matches()) { // It's just a pure imaginary number.
            imag = Double.parseDouble(s.substring(0, s.length()-1));
        } else {
            Matcher matcher = Pattern.compile(complexRegex1).matcher(s);
            if (matcher.matches()) { // It's like '20.02+12.25i'.
                real = Double.parseDouble(matcher.group("real"));
                imag = Double.parseDouble(matcher.group("imag"));
            } else {
                matcher = Pattern.compile(complexRegex2).matcher(s);
                if(matcher.matches()) { // It's like '12.25i+20.02'.
                    real = Double.parseDouble(matcher.group("real"));
                    imag = Double.parseDouble(matcher.group("imag"));
                } else {
                    throw new NumberFormatException("\""+ s + "\" can't be translated as a complex.");
                }
            }
        }
        return new Complex(real, imag);
    }


    /***** Arithmetic Operations *****/

    /**
     * Does this equal another complex within the allowed error range 1e-6?
     *
     * @param complex complex to be compared with
     * @return true / false
     */
    public boolean eq(Complex complex) {
        return Math.abs(real-complex.real)+Math.abs(imag-complex.imag) < 1e-6;
    }

    /**
     * Returns a new Complex whose value is {this + augend}
     *
     * @param augend complex to be added to this
     * @return {this + augend}
     */
    public Complex add(Complex augend) {
        return new Complex(this.real+augend.real, this.imag+augend.imag);
    }

    /**
     * Returns a new Complex whose value is {this + real}
     *
     * @param real real number to be added to this
     * @return {this + real}
     */
    public Complex add(double real) {
        return new Complex(this.real+real, this.imag);
    }

    /**
     * Returns a new Complex whose value is {this - subtrahend}
     *
     * @param subtrahend complex to be subtracted from this
     * @return {this - subtrahend}
     */
    public Complex sub(Complex subtrahend) {
        return new Complex(this.real-subtrahend.real, this.imag-subtrahend.imag);
    }

    public Complex sub(double real) {
        return new Complex(this.real-real, this.imag);
    }

    /**
     * Returns a new Complex whose value is {this * multiplicand}
     *
     * @param multiplicand complex to be multiplied by this
     * @return {this * multiplicand}
     */
    public Complex mul(Complex multiplicand) {
        double real = this.real*multiplicand.real - this.imag*multiplicand.imag;
        double imag = this.real*multiplicand.imag + this.imag*multiplicand.real;
        return new Complex(real, imag);
    }

    public Complex mul(double real) {
        return new Complex(this.real*real, this.imag*real);
    }

    /**
     * Returns a new Complex whose value is {this / divisor}
     *
     * @param divisor complex by which this is to be divided
     * @return {this / divisor}
     * @throws ArithmeticException if /0
     */
    public Complex div(Complex divisor) {
        double denominator = divisor.real*divisor.real + divisor.imag*divisor.imag;
        if (denominator == 0) {
            throw new ArithmeticException("Complex division by zero!");
        }
        double real = (this.real*divisor.real + this.imag*divisor.imag) / denominator;
        double imag = (this.imag*divisor.real - this.real*divisor.imag) / denominator;
        return new Complex(real, imag);
    }

    public Complex div(double real) {
        if (real == 0) {
            throw new ArithmeticException("Complex division by zero!");
        }
        return new Complex(this.real/real, this.imag/real);
    }

    /**
     * Returns the modulus value of a complex number ( 复数的模 )
     *
     * @return length of the vector in 2d plane
     */
    public double abs() {
        return Math.sqrt(real*real + imag*imag);
    }

    /**
     * Returns the modulus value of a complex number ( 复数的模 )
     *
     * @return length of the vector in 2d plane
     */
    public double mod() {
        return Math.sqrt(real*real + imag*imag);
    }

    /**
     * Returns the argument of a complex number ( 复数的辐角 )
     *
     * @return angle in radians of the vector in 2d plane (-PI~PI)
     */
    public double arg() {
        return Math.atan2(this.imag, this.real);
    }

    /**
     * Returns the inverse of a complex number ( 复数的倒数 )
     *
     * @return inverse of this
     * @throws ArithmeticException ZERO has no inverse.
     */
    public Complex inv() {
        double denominator = real*real + imag*imag;
        if (denominator == 0) {
            throw new ArithmeticException("ZERO has no inverse!");
        }
        double real = this.real / denominator;
        double imag = this.imag / denominator;
        return new Complex(real, imag);
    }

    /**
     * Returns  the numerical negative value of a complex number
     *
     * @return {0 - this}
     */
    public Complex neg() {
        return new Complex(-this.real, -this.imag);
    }

    /**
     * Returns the conjugate of a complex number
     *
     * @return conjugate of this
     */
    public Complex conj() {
        return new Complex(this.real, -this.imag);
    }

    /**
     * Returns the square root of a complex number
     *
     * @return square root of this
     */
    public Complex sqrt() {
        double mod = this.mod();
        double sqrt2 = Math.sqrt(2);
        double real =  Math.sqrt(mod + this.real) / sqrt2;
        double sgn = Math.signum(this.imag);
        if (sgn == 0.0) {
            sgn = 1.0;
        }
        double imag = Math.sqrt(mod - this.real) / sqrt2 * Math.signum(sgn);
        return new Complex(real, imag);
    }

    /**
     * Is this exactly ZERO?
     *
     * @return true / false
     */
    public boolean isZero() {
        return this.real == 0 && this.imag == 0;
    }

    /**
     * Is this a pure real number?
     *
     * @return true / false
     */
    public boolean isReal() {
        return this.imag == 0;
    }

    /**
     * Is this a pure imaginary number?
     *
     * @return true / false
     */
    public boolean isImag() {
        return this.real == 0;
    }

}


ComplexTest

/**
 * It tests some methods in Complex.
 *
 * @author Cloudy1225
 */
public class ComplexTest {

    private static final double delta = 1e-6;

    @Test
    public void testToString() {
        Complex complex1 = new Complex(2, -3);
        Complex complex2 = new Complex(2.5, 3.9);
        Complex complex3 = new Complex(0, -0.8);
        Complex complex4 = new Complex(1);
        Complex complex5 = new Complex(0, 0.8);
        Complex complex6 = Complex.ZERO;
        System.out.println(complex1);
        System.out.println(complex2);
        System.out.println(complex3);
        System.out.println(complex4);
        System.out.println(complex5);
        System.out.println(complex6);
    }

    @Test
    public void testDiv() {
        Complex complex1 = new Complex(10, -10);
        Complex complex2 = new Complex(3, 4);
        Complex res = complex1.div(complex2);
        System.out.println(res);
        Assert.assertTrue(res.eq(new Complex(-0.4, -2.8)));
        try {
            complex1.div(Complex.ZERO);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testSqrt() {
        Complex complex1 = new Complex(4);
        Assert.assertTrue(complex1.sqrt().eq(new Complex(2)));
        Complex complex2 = new Complex(1, 4);
        Complex sqrt = complex2.sqrt();
        System.out.println(sqrt);
        Complex mul = sqrt.mul(sqrt);
        System.out.println(mul);
        Assert.assertTrue(complex2.eq(mul));
    }

    @Test
    public void testArg() {
        Complex complex = new Complex(1, 1);
        double angel = complex.arg();
        System.out.println(complex.arg());
        Assert.assertEquals(complex.arg()*4, Math.PI, delta);
    }

    @Test
    public void testParseComplex() {
        Complex complex1 = Complex.parseComplex("1+5i");
        Complex complex2 = Complex.parseComplex("12.j+5");
        Complex complex3 = Complex.parseComplex("1e-3-2e3i");
        Complex complex4 = Complex.parseComplex("0+1.j");
        Complex complex5 = Complex.parseComplex(".5");
        System.out.println(complex1);
        System.out.println(complex2);
        System.out.println(complex3);
        System.out.println(complex4);
        System.out.println(complex5);
        try {
            Complex.parseComplex("0.2+ 3j");
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        try {
            Complex.parseComplex("0.2+3ja");
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }

}

你可能感兴趣的:(java,线性代数)