Author: psteitz Date: Sun Nov 18 15:38:05 2007 New Revision: 596159 URL: http://svn.apache.org/viewvc?rev=596159&view=rev Log: Merged most functions from ComplexUtils into Complex class, added static factory method to Complex. JIRA: MATH-171 Reported and patched by Niall Pemberton
Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java commons/proper/math/trunk/src/java/org/apache/commons/math/complex/ComplexUtils.java commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java commons/proper/math/trunk/xdocs/changes.xml Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java?rev=596159&r1=596158&r2=596159&view=diff ============================================================================== --- commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java (original) +++ commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java Sun Nov 18 15:38:05 2007 @@ -124,7 +124,7 @@ * @throws NullPointerException if <code>rhs</code> is null */ public Complex add(Complex rhs) { - return new Complex(real + rhs.getReal(), + return createComplex(real + rhs.getReal(), imaginary + rhs.getImaginary()); } @@ -146,7 +146,7 @@ if (isNaN()) { return NaN; } - return new Complex(real, -imaginary); + return createComplex(real, -imaginary); } /** @@ -201,19 +201,19 @@ if (Math.abs(c) < Math.abs(d)) { if (d == 0.0) { - return new Complex(real/c, imaginary/c); + return createComplex(real/c, imaginary/c); } double q = c / d; double denominator = c * q + d; - return new Complex((real * q + imaginary) / denominator, + return createComplex((real * q + imaginary) / denominator, (imaginary * q - real) / denominator); } else { if (c == 0.0) { - return new Complex(imaginary/d, -real/c); + return createComplex(imaginary/d, -real/c); } double q = d / c; double denominator = d * q + c; - return new Complex((imaginary * q + real) / denominator, + return createComplex((imaginary * q + real) / denominator, (imaginary - real * q) / denominator); } } @@ -349,7 +349,7 @@ if (isNaN() || rhs.isNaN()) { return NaN; } - return new Complex(real * rhs.real - imaginary * rhs.imaginary, + return createComplex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + imaginary * rhs.real); } @@ -366,7 +366,7 @@ return NaN; } - return new Complex(-real, -imaginary); + return createComplex(-real, -imaginary); } /** @@ -392,7 +392,472 @@ return NaN; } - return new Complex(real - rhs.getReal(), + return createComplex(real - rhs.getReal(), imaginary - rhs.getImaginary()); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/InverseCosine.html" TARGET="_top"> + * inverse cosine</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> acos(z) = -i (log(z + i (sqrt(1 - z<sup>2</sup>))))</code></pre> + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code> or infinite. + * + * @return the inverse cosine of this complex number + * @since 1.2 + */ + public Complex acos() { + if (isNaN()) { + return Complex.NaN; + } + + return this.add(this.sqrt1z().multiply(Complex.I)).log() + .multiply(Complex.I.negate()); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/InverseSine.html" TARGET="_top"> + * inverse sine</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> asin(z) = -i (log(sqrt(1 - z<sup>2</sup>) + iz)) </code></pre> + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code> or infinite. + * + * @return the inverse sine of this complex number. + * @since 1.2 + */ + public Complex asin() { + if (isNaN()) { + return Complex.NaN; + } + + return sqrt1z().add(this.multiply(Complex.I)).log() + .multiply(Complex.I.negate()); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/InverseTangent.html" TARGET="_top"> + * inverse tangent</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> atan(z) = (i/2) log((i + z)/(i - z)) </code></pre> + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code> or infinite. + * + * @return the inverse tangent of this complex number + * @since 1.2 + */ + public Complex atan() { + if (isNaN()) { + return Complex.NaN; + } + + return this.add(Complex.I).divide(Complex.I.subtract(this)).log() + .multiply(Complex.I.divide(createComplex(2.0, 0.0))); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/Cosine.html" TARGET="_top"> + * cosine</a> + * of this complex number. + * <p> + * Implements the formula: <pre> + * <code> cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * cos(1 ± INFINITY i) = 1 ∓ INFINITY i + * cos(±INFINITY + i) = NaN + NaN i + * cos(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre> + * + * @return the cosine of this complex number + * @since 1.2 + */ + public Complex cos() { + if (isNaN()) { + return Complex.NaN; + } + + return createComplex(Math.cos(real) * MathUtils.cosh(imaginary), + -Math.sin(real) * MathUtils.sinh(imaginary)); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/HyperbolicCosine.html" TARGET="_top"> + * hyperbolic cosine</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> cosh(a + bi) = cosh(a)cos(b) + sinh(a)sin(b)i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * cosh(1 ± INFINITY i) = NaN + NaN i + * cosh(±INFINITY + i) = INFINITY ± INFINITY i + * cosh(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre> + * + * @return the hyperbolic cosine of this complex number. + * @since 1.2 + */ + public Complex cosh() { + if (isNaN()) { + return Complex.NaN; + } + + return createComplex(MathUtils.cosh(real) * Math.cos(imaginary), + MathUtils.sinh(real) * Math.sin(imaginary)); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/ExponentialFunction.html" TARGET="_top"> + * exponential function</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> exp(a + bi) = exp(a)cos(b) + exp(a)sin(b)i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#exp}, [EMAIL PROTECTED] java.lang.Math#cos}, and + * [EMAIL PROTECTED] java.lang.Math#sin}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * exp(1 ± INFINITY i) = NaN + NaN i + * exp(INFINITY + i) = INFINITY + INFINITY i + * exp(-INFINITY + i) = 0 + 0i + * exp(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre> + * + * @return <i>e</i><sup><code>this</code></sup> + * @since 1.2 + */ + public Complex exp() { + if (isNaN()) { + return Complex.NaN; + } + + double expReal = Math.exp(real); + return createComplex(expReal * Math.cos(imaginary), expReal * Math.sin(imaginary)); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/NaturalLogarithm.html" TARGET="_top"> + * natural logarithm</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> log(a + bi) = ln(|a + bi|) + arg(a + bi)i</code></pre> + * where ln on the right hand side is [EMAIL PROTECTED] java.lang.Math#log}, + * <code>|a + bi|</code> is the modulus, [EMAIL PROTECTED] Complex#abs}, and + * <code>arg(a + bi) = [EMAIL PROTECTED] java.lang.Math#atan2}(b, a)</code> + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite (or critical) values in real or imaginary parts of the input may + * result in infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * log(1 ± INFINITY i) = INFINITY ± (π/2)i + * log(INFINITY + i) = INFINITY + 0i + * log(-INFINITY + i) = INFINITY + πi + * log(INFINITY ± INFINITY i) = INFINITY ± (π/4)i + * log(-INFINITY ± INFINITY i) = INFINITY ± (3π/4)i + * log(0 + 0i) = -INFINITY + 0i + * </code></pre> + * + * @return ln of this complex number. + * @since 1.2 + */ + public Complex log() { + if (isNaN()) { + return Complex.NaN; + } + + return createComplex(Math.log(abs()), + Math.atan2(imaginary, real)); + } + + /** + * Returns of value of this complex number raised to the power of <code>x</code>. + * <p> + * Implements the formula: <pre> + * <code> y<sup>x</sup> = exp(x·log(y))</code></pre> + * where <code>exp</code> and <code>log</code> are [EMAIL PROTECTED] #exp} and + * [EMAIL PROTECTED] #log}, respectively. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code> or infinite, or if <code>y</code> + * equals [EMAIL PROTECTED] Complex#ZERO}. + * + * @param x the exponent. + * @return <code>this</code><sup><code>x</code></sup> + * @throws NullPointerException if x is null + * @since 1.2 + */ + public Complex pow(Complex x) { + if (x == null) { + throw new NullPointerException(); + } + return this.log().multiply(x).exp(); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/Sine.html" TARGET="_top"> + * sine</a> + * of this complex number. + * <p> + * Implements the formula: <pre> + * <code> sin(a + bi) = sin(a)cosh(b) - cos(a)sinh(b)i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * sin(1 ± INFINITY i) = 1 ± INFINITY i + * sin(±INFINITY + i) = NaN + NaN i + * sin(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre> + * + * @return the sine of this complex number. + * @since 1.2 + */ + public Complex sin() { + if (isNaN()) { + return Complex.NaN; + } + + return createComplex(Math.sin(real) * MathUtils.cosh(imaginary), + Math.cos(real) * MathUtils.sinh(imaginary)); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/HyperbolicSine.html" TARGET="_top"> + * hyperbolic sine</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code> sinh(a + bi) = sinh(a)cos(b)) + cosh(a)sin(b)i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * sinh(1 ± INFINITY i) = NaN + NaN i + * sinh(±INFINITY + i) = ± INFINITY + INFINITY i + * sinh(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre + * + * @return the hyperbolic sine of this complex number + * @since 1.2 + */ + public Complex sinh() { + if (isNaN()) { + return Complex.NaN; + } + + return createComplex(MathUtils.sinh(real) * Math.cos(imaginary), + MathUtils.cosh(real) * Math.sin(imaginary)); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top"> + * square root</a> of this complex number. + * <p> + * Implements the following algorithm to compute <code>sqrt(a + bi)</code>: + * <ol><li>Let <code>t = sqrt((|a| + |a + bi|) / 2)</code></li> + * <li><pre>if <code> a ≥ 0</code> return <code>t + (b/2t)i</code> + * else return <code>|b|/2t + sign(b)t i </code></pre></li> + * </ol> + * where <ul> + * <li><code>|a| = [EMAIL PROTECTED] Math#abs}(a)</code></li> + * <li><code>|a + bi| = [EMAIL PROTECTED] Complex#abs}(a + bi) </code></li> + * <li><code>sign(b) = [EMAIL PROTECTED] MathUtils#indicator}(b) </code> + * </ul> + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * sqrt(1 ± INFINITY i) = INFINITY + NaN i + * sqrt(INFINITY + i) = INFINITY + 0i + * sqrt(-INFINITY + i) = 0 + INFINITY i + * sqrt(INFINITY ± INFINITY i) = INFINITY + NaN i + * sqrt(-INFINITY ± INFINITY i) = NaN ± INFINITY i + * </code></pre> + * + * @return the square root of this complex number + * @since 1.2 + */ + public Complex sqrt() { + if (isNaN()) { + return Complex.NaN; + } + + if (real == 0.0 && imaginary == 0.0) { + return createComplex(0.0, 0.0); + } + + double t = Math.sqrt((Math.abs(real) + abs()) / 2.0); + if (real >= 0.0) { + return createComplex(t, imaginary / (2.0 * t)); + } else { + return createComplex(Math.abs(imaginary) / (2.0 * t), + MathUtils.indicator(imaginary) * t); + } + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top"> + * square root</a> of 1 - <code>this</code><sup>2</sup> for this complex + * number. + * <p> + * Computes the result directly as + * <code>sqrt(Complex.ONE.subtract(z.multiply(z)))</code>. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result. + * + * @return the square root of 1 - <code>this</code><sup>2</sup> + * @since 1.2 + */ + public Complex sqrt1z() { + return createComplex(1.0, 0.0).subtract(this.multiply(this)).sqrt(); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/Tangent.html" TARGET="_top"> + * tangent</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code>tan(a + bi) = sin(2a)/(cos(2a)+cosh(2b)) + [sinh(2b)/(cos(2a)+cosh(2b))]i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite (or critical) values in real or imaginary parts of the input may + * result in infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * tan(1 ± INFINITY i) = 0 + NaN i + * tan(±INFINITY + i) = NaN + NaN i + * tan(±INFINITY ± INFINITY i) = NaN + NaN i + * tan(±π/2 + 0 i) = ±INFINITY + NaN i</code></pre> + * + * @return the tangent of this complex number + * @since 1.2 + */ + public Complex tan() { + if (isNaN()) { + return Complex.NaN; + } + + double real2 = 2.0 * real; + double imaginary2 = 2.0 * imaginary; + double d = Math.cos(real2) + MathUtils.cosh(imaginary2); + + return createComplex(Math.sin(real2) / d, MathUtils.sinh(imaginary2) / d); + } + + /** + * Compute the + * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html" TARGET="_top"> + * hyperbolic tangent</a> of this complex number. + * <p> + * Implements the formula: <pre> + * <code>tan(a + bi) = sinh(2a)/(cosh(2a)+cos(2b)) + [sin(2b)/(cosh(2a)+cos(2b))]i</code></pre> + * where the (real) functions on the right-hand side are + * [EMAIL PROTECTED] java.lang.Math#sin}, [EMAIL PROTECTED] java.lang.Math#cos}, + * [EMAIL PROTECTED] MathUtils#cosh} and [EMAIL PROTECTED] MathUtils#sinh}. + * <p> + * Returns [EMAIL PROTECTED] Complex#NaN} if either real or imaginary part of the + * input argument is <code>NaN</code>. + * <p> + * Infinite values in real or imaginary parts of the input may result in + * infinite or NaN values returned in parts of the result.<pre> + * Examples: + * <code> + * tanh(1 ± INFINITY i) = NaN + NaN i + * tanh(±INFINITY + i) = NaN + 0 i + * tanh(±INFINITY ± INFINITY i) = NaN + NaN i + * tanh(0 + (π/2)i) = NaN + INFINITY i</code></pre> + * + * @return the hyperbolic tangent of this complex number + * @since 1.2 + */ + public Complex tanh() { + if (isNaN()) { + return Complex.NaN; + } + + double real2 = 2.0 * real; + double imaginary2 = 2.0 * imaginary; + double d = MathUtils.cosh(real2) + Math.cos(imaginary2); + + return createComplex(MathUtils.sinh(real2) / d, Math.sin(imaginary2) / d); + } + + /** + * Create a complex number given the real and imaginary parts. + * + * @param real the real part + * @param imaginary the imaginary part + * @return a new complex number instance + * @since 1.2 + */ + protected Complex createComplex(double real, double imaginary) { + return new Complex(real, imaginary); } } Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/complex/ComplexUtils.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/complex/ComplexUtils.java?rev=596159&r1=596158&r2=596159&view=diff ============================================================================== --- commons/proper/math/trunk/src/java/org/apache/commons/math/complex/ComplexUtils.java (original) +++ commons/proper/math/trunk/src/java/org/apache/commons/math/complex/ComplexUtils.java Sun Nov 18 15:38:05 2007 @@ -60,14 +60,10 @@ * @param z the value whose inverse cosine is to be returned * @return the inverse cosine of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.acos() */ public static Complex acos(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - return Complex.I.negate().multiply(log(z.add( - Complex.I.multiply(sqrt1z(z))))); + return z.acos(); } /** @@ -84,14 +80,10 @@ * @param z the value whose inverse sine is to be returned. * @return the inverse sine of <code>z</code>. * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.asin() */ public static Complex asin(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - return Complex.I.negate().multiply(log(sqrt1z(z).add( - Complex.I.multiply(z)))); + return z.asin(); } /** @@ -108,15 +100,10 @@ * @param z the value whose inverse tangent is to be returned * @return the inverse tangent of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.atan() */ public static Complex atan(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - return Complex.I.multiply( - log(Complex.I.add(z).divide(Complex.I.subtract(z)))) - .divide(new Complex(2.0, 0.0)); + return z.atan(); } /** @@ -145,17 +132,10 @@ * @param z the value whose cosine is to be returned * @return the cosine of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.cos() */ public static Complex cos(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a = z.getReal(); - double b = z.getImaginary(); - - return new Complex(Math.cos(a) * MathUtils.cosh(b), - -Math.sin(a) * MathUtils.sinh(b)); + return z.cos(); } /** @@ -184,17 +164,10 @@ * * @param z the value whose hyperbolic cosine is to be returned. * @return the hyperbolic cosine of <code>z</code>. + * @deprecated use Complex.cosh() */ public static Complex cosh(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a = z.getReal(); - double b = z.getImaginary(); - - return new Complex(MathUtils.cosh(a) * Math.cos(b), - MathUtils.sinh(a) * Math.sin(b)); + return z.cosh(); } /** @@ -224,15 +197,10 @@ * * @param z the value * @return <i>e</i><sup><code>z</code></sup> + * @deprecated use Complex.exp() */ public static Complex exp(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double b = z.getImaginary(); - double expA = Math.exp(z.getReal()); - return new Complex(expA * Math.cos(b), expA * Math.sin(b)); + return z.exp(); } /** @@ -264,14 +232,10 @@ * * @param z the value. * @return ln <code>z</code>. + * @deprecated use Complex.log() */ public static Complex log(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - return new Complex(Math.log(z.abs()), - Math.atan2(z.getImaginary(), z.getReal())); + return z.log(); } /** @@ -323,9 +287,10 @@ * @param x the exponent. * @return <code>y</code><sup><code>x</code></sup> * @throws NullPointerException if either x or y is null + * @deprecated use Complex.pow(x) */ public static Complex pow(Complex y, Complex x) { - return exp(x.multiply(log(y))); + return y.pow(x); } /** @@ -355,17 +320,10 @@ * * @param z the value whose sine is to be returned. * @return the sine of <code>z</code>. + * @deprecated use Complex.sin() */ public static Complex sin(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a = z.getReal(); - double b = z.getImaginary(); - - return new Complex(Math.sin(a) * MathUtils.cosh(b), - Math.cos(a) * MathUtils.sinh(b)); + return z.sin(); } /** @@ -393,17 +351,10 @@ * @param z the value whose hyperbolic sine is to be returned * @return the hyperbolic sine of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.sinh() */ public static Complex sinh(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a = z.getReal(); - double b = z.getImaginary(); - - return new Complex(MathUtils.sinh(a) * Math.cos(b), - MathUtils.cosh(a) * Math.sin(b)); + return z.sinh(); } /** @@ -439,25 +390,10 @@ * @param z the value whose square root is to be returned * @return the square root of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.sqrt() */ public static Complex sqrt(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a = z.getReal(); - double b = z.getImaginary(); - if (a == 0.0 && b == 0.0) { - return new Complex(0.0, 0.0); - } - - double t = Math.sqrt((Math.abs(a) + z.abs()) / 2.0); - if (a >= 0.0) { - return new Complex(t, b / (2.0 * t)); - } else { - return new Complex(Math.abs(b) / (2.0 * t), - MathUtils.indicator(b) * t); - } + return z.sqrt(); } /** @@ -478,9 +414,10 @@ * @param z the value * @return the square root of 1 - <code>z</code><sup>2</sup> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.sqrt1z() */ public static Complex sqrt1z(Complex z) { - return sqrt(Complex.ONE.subtract(z.multiply(z))); + return z.sqrt1z(); } /** @@ -509,17 +446,10 @@ * @param z the value whose tangent is to be returned * @return the tangent of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.tan() */ public static Complex tan(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a2 = 2.0 * z.getReal(); - double b2 = 2.0 * z.getImaginary(); - double d = Math.cos(a2) + MathUtils.cosh(b2); - - return new Complex(Math.sin(a2) / d, MathUtils.sinh(b2) / d); + return z.tan(); } /** @@ -548,16 +478,9 @@ * @param z the value whose hyperbolic tangent is to be returned * @return the hyperbolic tangent of <code>z</code> * @throws NullPointerException if <code>z</code> is null + * @deprecated use Complex.tanh() */ public static Complex tanh(Complex z) { - if (z.isNaN()) { - return Complex.NaN; - } - - double a2 = 2.0 * z.getReal(); - double b2 = 2.0 * z.getImaginary(); - double d = MathUtils.cosh(a2) + Math.cos(b2); - - return new Complex(MathUtils.sinh(a2) / d, Math.sin(b2) / d); + return z.tanh(); } } Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java?rev=596159&r1=596158&r2=596159&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java (original) +++ commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java Sun Nov 18 15:38:05 2007 @@ -17,6 +17,8 @@ package org.apache.commons.math.complex; +import org.apache.commons.math.TestUtils; + import junit.framework.TestCase; /** @@ -27,12 +29,25 @@ private double inf = Double.POSITIVE_INFINITY; private double neginf = Double.NEGATIVE_INFINITY; private double nan = Double.NaN; + private double pi = Math.PI; private Complex oneInf = new Complex(1, inf); private Complex oneNegInf = new Complex(1, neginf); private Complex infOne = new Complex(inf, 1); + private Complex infZero = new Complex(inf, 0); + private Complex infNaN = new Complex(inf, nan); + private Complex infNegInf = new Complex(inf, neginf); + private Complex infInf = new Complex(inf, inf); private Complex negInfInf = new Complex(neginf, inf); + private Complex negInfZero = new Complex(neginf, 0); + private Complex negInfOne = new Complex(neginf, 1); + private Complex negInfNaN = new Complex(neginf, nan); private Complex negInfNegInf = new Complex(neginf, neginf); private Complex oneNaN = new Complex(1, nan); + private Complex zeroInf = new Complex(0, inf); + private Complex zeroNaN = new Complex(0, nan); + private Complex nanInf = new Complex(nan, inf); + private Complex nanNegInf = new Complex(nan, neginf); + private Complex nanZero = new Complex(nan, 0); public void testConstructor() { Complex z = new Complex(3.0, 4.0); @@ -274,5 +289,400 @@ Complex imaginaryNaN = new Complex(0.0, Double.NaN); assertEquals(realNaN.hashCode(), imaginaryNaN.hashCode()); assertEquals(imaginaryNaN.hashCode(), Complex.NaN.hashCode()); + } + + public void testAcos() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(0.936812, -2.30551); + TestUtils.assertEquals(expected, z.acos(), 1.0e-5); + TestUtils.assertEquals(new Complex(Math.acos(0), 0), + Complex.ZERO.acos(), 1.0e-12); + } + + public void testAcosInf() { + TestUtils.assertSame(Complex.NaN, oneInf.acos()); + TestUtils.assertSame(Complex.NaN, oneNegInf.acos()); + TestUtils.assertSame(Complex.NaN, infOne.acos()); + TestUtils.assertSame(Complex.NaN, negInfOne.acos()); + TestUtils.assertSame(Complex.NaN, infInf.acos()); + TestUtils.assertSame(Complex.NaN, infNegInf.acos()); + TestUtils.assertSame(Complex.NaN, negInfInf.acos()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.acos()); + } + + public void testAcosNaN() { + assertTrue(Complex.NaN.acos().isNaN()); + } + + public void testAsin() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(0.633984, 2.30551); + TestUtils.assertEquals(expected, z.asin(), 1.0e-5); + } + + public void testAsinNaN() { + assertTrue(Complex.NaN.asin().isNaN()); + } + + public void testAsinInf() { + TestUtils.assertSame(Complex.NaN, oneInf.asin()); + TestUtils.assertSame(Complex.NaN, oneNegInf.asin()); + TestUtils.assertSame(Complex.NaN, infOne.asin()); + TestUtils.assertSame(Complex.NaN, negInfOne.asin()); + TestUtils.assertSame(Complex.NaN, infInf.asin()); + TestUtils.assertSame(Complex.NaN, infNegInf.asin()); + TestUtils.assertSame(Complex.NaN, negInfInf.asin()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.asin()); + } + + + public void testAtan() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(1.44831, 0.158997); + TestUtils.assertEquals(expected, z.atan(), 1.0e-5); + } + + public void testAtanInf() { + TestUtils.assertSame(Complex.NaN, oneInf.atan()); + TestUtils.assertSame(Complex.NaN, oneNegInf.atan()); + TestUtils.assertSame(Complex.NaN, infOne.atan()); + TestUtils.assertSame(Complex.NaN, negInfOne.atan()); + TestUtils.assertSame(Complex.NaN, infInf.atan()); + TestUtils.assertSame(Complex.NaN, infNegInf.atan()); + TestUtils.assertSame(Complex.NaN, negInfInf.atan()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.atan()); + } + + public void testAtanNaN() { + assertTrue(Complex.NaN.atan().isNaN()); + assertTrue(Complex.I.atan().isNaN()); + } + + public void testCos() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(-27.03495, -3.851153); + TestUtils.assertEquals(expected, z.cos(), 1.0e-5); + } + + public void testCosNaN() { + assertTrue(Complex.NaN.cos().isNaN()); + } + + public void testCosInf() { + TestUtils.assertSame(infNegInf, oneInf.cos()); + TestUtils.assertSame(infInf, oneNegInf.cos()); + TestUtils.assertSame(Complex.NaN, infOne.cos()); + TestUtils.assertSame(Complex.NaN, negInfOne.cos()); + TestUtils.assertSame(Complex.NaN, infInf.cos()); + TestUtils.assertSame(Complex.NaN, infNegInf.cos()); + TestUtils.assertSame(Complex.NaN, negInfInf.cos()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.cos()); + } + + public void testCosh() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(-6.58066, -7.58155); + TestUtils.assertEquals(expected, z.cosh(), 1.0e-5); + } + + public void testCoshNaN() { + assertTrue(Complex.NaN.cosh().isNaN()); + } + + public void testCoshInf() { + TestUtils.assertSame(Complex.NaN, oneInf.cosh()); + TestUtils.assertSame(Complex.NaN, oneNegInf.cosh()); + TestUtils.assertSame(infInf, infOne.cosh()); + TestUtils.assertSame(infNegInf, negInfOne.cosh()); + TestUtils.assertSame(Complex.NaN, infInf.cosh()); + TestUtils.assertSame(Complex.NaN, infNegInf.cosh()); + TestUtils.assertSame(Complex.NaN, negInfInf.cosh()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.cosh()); + } + + public void testExp() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(-13.12878, -15.20078); + TestUtils.assertEquals(expected, z.exp(), 1.0e-5); + TestUtils.assertEquals(Complex.ONE, + Complex.ZERO.exp(), 10e-12); + Complex iPi = Complex.I.multiply(new Complex(pi,0)); + TestUtils.assertEquals(Complex.ONE.negate(), + iPi.exp(), 10e-12); + } + + public void testExpNaN() { + assertTrue(Complex.NaN.exp().isNaN()); + } + + public void testExpInf() { + TestUtils.assertSame(Complex.NaN, oneInf.exp()); + TestUtils.assertSame(Complex.NaN, oneNegInf.exp()); + TestUtils.assertSame(infInf, infOne.exp()); + TestUtils.assertSame(Complex.ZERO, negInfOne.exp()); + TestUtils.assertSame(Complex.NaN, infInf.exp()); + TestUtils.assertSame(Complex.NaN, infNegInf.exp()); + TestUtils.assertSame(Complex.NaN, negInfInf.exp()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.exp()); + } + + public void testLog() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(1.60944, 0.927295); + TestUtils.assertEquals(expected, z.log(), 1.0e-5); + } + + public void testLogNaN() { + assertTrue(Complex.NaN.log().isNaN()); + } + + public void testLogInf() { + TestUtils.assertEquals(new Complex(inf, pi / 2), + oneInf.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, -pi / 2), + oneNegInf.log(), 10e-12); + TestUtils.assertEquals(infZero, infOne.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, pi), + negInfOne.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, pi / 4), + infInf.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, -pi / 4), + infNegInf.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, 3d * pi / 4), + negInfInf.log(), 10e-12); + TestUtils.assertEquals(new Complex(inf, - 3d * pi / 4), + negInfNegInf.log(), 10e-12); + } + + public void testLogZero() { + TestUtils.assertSame(negInfZero, Complex.ZERO.log()); + } + + public void testPow() { + Complex x = new Complex(3, 4); + Complex y = new Complex(5, 6); + Complex expected = new Complex(-1.860893, 11.83677); + TestUtils.assertEquals(expected, x.pow(y), 1.0e-5); + } + + public void testPowNaNBase() { + Complex x = new Complex(3, 4); + assertTrue(Complex.NaN.pow(x).isNaN()); + } + + public void testPowNaNExponent() { + Complex x = new Complex(3, 4); + assertTrue(x.pow(Complex.NaN).isNaN()); + } + + public void testPowInf() { + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(oneInf)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(oneNegInf)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(infOne)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(infInf)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(infNegInf)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(negInfInf)); + TestUtils.assertSame(Complex.NaN,Complex.ONE.pow(negInfNegInf)); + TestUtils.assertSame(Complex.NaN,infOne.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,negInfOne.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,infInf.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,infNegInf.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,negInfInf.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,negInfNegInf.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN,negInfNegInf.pow(infNegInf)); + TestUtils.assertSame(Complex.NaN,negInfNegInf.pow(negInfNegInf)); + TestUtils.assertSame(Complex.NaN,negInfNegInf.pow(infInf)); + TestUtils.assertSame(Complex.NaN,infInf.pow(infNegInf)); + TestUtils.assertSame(Complex.NaN,infInf.pow(negInfNegInf)); + TestUtils.assertSame(Complex.NaN,infInf.pow(infInf)); + TestUtils.assertSame(Complex.NaN,infNegInf.pow(infNegInf)); + TestUtils.assertSame(Complex.NaN,infNegInf.pow(negInfNegInf)); + TestUtils.assertSame(Complex.NaN,infNegInf.pow(infInf)); + } + + public void testPowZero() { + TestUtils.assertSame(Complex.NaN, + Complex.ZERO.pow(Complex.ONE)); + TestUtils.assertSame(Complex.NaN, + Complex.ZERO.pow(Complex.ZERO)); + TestUtils.assertSame(Complex.NaN, + Complex.ZERO.pow(Complex.I)); + TestUtils.assertEquals(Complex.ONE, + Complex.ONE.pow(Complex.ZERO), 10e-12); + TestUtils.assertEquals(Complex.ONE, + Complex.I.pow(Complex.ZERO), 10e-12); + TestUtils.assertEquals(Complex.ONE, + new Complex(-1, 3).pow(Complex.ZERO), 10e-12); + } + + public void testpowNull() { + try { + Complex.ONE.pow(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + + public void testSin() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(3.853738, -27.01681); + TestUtils.assertEquals(expected, z.sin(), 1.0e-5); + } + + public void testSinInf() { + TestUtils.assertSame(infInf, oneInf.sin()); + TestUtils.assertSame(infNegInf, oneNegInf.sin()); + TestUtils.assertSame(Complex.NaN, infOne.sin()); + TestUtils.assertSame(Complex.NaN, negInfOne.sin()); + TestUtils.assertSame(Complex.NaN, infInf.sin()); + TestUtils.assertSame(Complex.NaN, infNegInf.sin()); + TestUtils.assertSame(Complex.NaN, negInfInf.sin()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.sin()); + } + + public void testSinNaN() { + assertTrue(Complex.NaN.sin().isNaN()); + } + + public void testSinh() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(-6.54812, -7.61923); + TestUtils.assertEquals(expected, z.sinh(), 1.0e-5); + } + + public void testSinhNaN() { + assertTrue(Complex.NaN.sinh().isNaN()); + } + + public void testSinhInf() { + TestUtils.assertSame(Complex.NaN, oneInf.sinh()); + TestUtils.assertSame(Complex.NaN, oneNegInf.sinh()); + TestUtils.assertSame(infInf, infOne.sinh()); + TestUtils.assertSame(negInfInf, negInfOne.sinh()); + TestUtils.assertSame(Complex.NaN, infInf.sinh()); + TestUtils.assertSame(Complex.NaN, infNegInf.sinh()); + TestUtils.assertSame(Complex.NaN, negInfInf.sinh()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.sinh()); + } + + public void testSqrtRealPositive() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(2, 1); + TestUtils.assertEquals(expected, z.sqrt(), 1.0e-5); + } + + public void testSqrtRealZero() { + Complex z = new Complex(0.0, 4); + Complex expected = new Complex(1.41421, 1.41421); + TestUtils.assertEquals(expected, z.sqrt(), 1.0e-5); + } + + public void testSqrtRealNegative() { + Complex z = new Complex(-3.0, 4); + Complex expected = new Complex(1, 2); + TestUtils.assertEquals(expected, z.sqrt(), 1.0e-5); + } + + public void testSqrtImaginaryZero() { + Complex z = new Complex(-3.0, 0.0); + Complex expected = new Complex(0.0, 1.73205); + TestUtils.assertEquals(expected, z.sqrt(), 1.0e-5); + } + + public void testSqrtImaginaryNegative() { + Complex z = new Complex(-3.0, -4.0); + Complex expected = new Complex(1.0, -2.0); + TestUtils.assertEquals(expected, z.sqrt(), 1.0e-5); + } + + public void testSqrtPolar() { + double r = 1; + for (int i = 0; i < 5; i++) { + r += i; + double theta = 0; + for (int j =0; j < 11; j++) { + theta += pi /12; + Complex z = ComplexUtils.polar2Complex(r, theta); + Complex sqrtz = ComplexUtils.polar2Complex(Math.sqrt(r), theta / 2); + TestUtils.assertEquals(sqrtz, z.sqrt(), 10e-12); + } + } + } + + public void testSqrtNaN() { + assertTrue(Complex.NaN.sqrt().isNaN()); + } + + public void testSqrtInf() { + TestUtils.assertSame(infNaN, oneInf.sqrt()); + TestUtils.assertSame(infNaN, oneNegInf.sqrt()); + TestUtils.assertSame(infZero, infOne.sqrt()); + TestUtils.assertSame(zeroInf, negInfOne.sqrt()); + TestUtils.assertSame(infNaN, infInf.sqrt()); + TestUtils.assertSame(infNaN, infNegInf.sqrt()); + TestUtils.assertSame(nanInf, negInfInf.sqrt()); + TestUtils.assertSame(nanNegInf, negInfNegInf.sqrt()); + } + + public void testSqrt1z() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(4.08033, -2.94094); + TestUtils.assertEquals(expected, z.sqrt1z(), 1.0e-5); + } + + public void testSqrt1zNaN() { + assertTrue(Complex.NaN.sqrt1z().isNaN()); + } + + public void testTan() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(-0.000187346, 0.999356); + TestUtils.assertEquals(expected, z.tan(), 1.0e-5); + } + + public void testTanNaN() { + assertTrue(Complex.NaN.tan().isNaN()); + } + + public void testTanInf() { + TestUtils.assertSame(zeroNaN, oneInf.tan()); + TestUtils.assertSame(zeroNaN, oneNegInf.tan()); + TestUtils.assertSame(Complex.NaN, infOne.tan()); + TestUtils.assertSame(Complex.NaN, negInfOne.tan()); + TestUtils.assertSame(Complex.NaN, infInf.tan()); + TestUtils.assertSame(Complex.NaN, infNegInf.tan()); + TestUtils.assertSame(Complex.NaN, negInfInf.tan()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.tan()); + } + + public void testTanCritical() { + TestUtils.assertSame(infNaN, new Complex(pi/2, 0).tan()); + TestUtils.assertSame(negInfNaN, new Complex(-pi/2, 0).tan()); + } + + public void testTanh() { + Complex z = new Complex(3, 4); + Complex expected = new Complex(1.00071, 0.00490826); + TestUtils.assertEquals(expected, z.tanh(), 1.0e-5); + } + + public void testTanhNaN() { + assertTrue(Complex.NaN.tanh().isNaN()); + } + + public void testTanhInf() { + TestUtils.assertSame(Complex.NaN, oneInf.tanh()); + TestUtils.assertSame(Complex.NaN, oneNegInf.tanh()); + TestUtils.assertSame(nanZero, infOne.tanh()); + TestUtils.assertSame(nanZero, negInfOne.tanh()); + TestUtils.assertSame(Complex.NaN, infInf.tanh()); + TestUtils.assertSame(Complex.NaN, infNegInf.tanh()); + TestUtils.assertSame(Complex.NaN, negInfInf.tanh()); + TestUtils.assertSame(Complex.NaN, negInfNegInf.tanh()); + } + + public void testTanhCritical() { + TestUtils.assertSame(nanInf, new Complex(0, pi/2).tanh()); } } Modified: commons/proper/math/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/xdocs/changes.xml?rev=596159&r1=596158&r2=596159&view=diff ============================================================================== --- commons/proper/math/trunk/xdocs/changes.xml (original) +++ commons/proper/math/trunk/xdocs/changes.xml Sun Nov 18 15:38:05 2007 @@ -40,6 +40,10 @@ </properties> <body> <release version="1.2-SNAPSHOT" date="TBD"> + <action dev="psteitz" type="update" issue="MATH-171" due-to="Niall Pemberton"> + Merged most functions from ComplexUtils into Complex class, added + static factory method to Complex. + </action> <action dev="luc" type="fix"> Fixed numerous warnings in test code. </action>