Author: psteitz Date: Wed Nov 23 09:43:57 2005 New Revision: 348502 URL: http://svn.apache.org/viewcvs?rev=348502&view=rev Log: * Added polar2Complex method to ComplexUtils to create Complex numbers from polar representations. * Improved documentation and test cases related to handling of infinite and NaN values in Complex, ComplexUtils classes. BZ #37086.
Modified: jakarta/commons/proper/math/branches/MATH_1_1/project.xml jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/Complex.java jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/ComplexUtils.java jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/TestUtils.java jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexUtilsTest.java jakarta/commons/proper/math/branches/MATH_1_1/xdocs/changes.xml jakarta/commons/proper/math/branches/MATH_1_1/xdocs/userguide/complex.xml Modified: jakarta/commons/proper/math/branches/MATH_1_1/project.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/project.xml?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/project.xml (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/project.xml Wed Nov 23 09:43:57 2005 @@ -205,8 +205,8 @@ <reports> <report>maven-changes-plugin</report> <report>maven-checkstyle-plugin</report> - <report>maven-clover-plugin</report> <!-- + <report>maven-clover-plugin</report> <report>maven-changelog-plugin</report> <report>maven-developer-activity-plugin</report> <report>maven-file-activity-plugin</report> Modified: jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/Complex.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/Complex.java?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/Complex.java (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/Complex.java Wed Nov 23 09:43:57 2005 @@ -23,11 +23,11 @@ * Representation of a Complex number - a number which has both a * real and imaginary part. * <p> - * Implementation of arithmetic operations handles <code>NaN</code> and + * Implementations of arithmetic operations handle <code>NaN</code> and * infinite values according to the rules for [EMAIL PROTECTED] java.lang.Double} * arithmetic, applying definitional formulas and returning <code>NaN</code> or * infinite values in real or imaginary parts as these arise in computation. - * See the javadoc for individual methods for details. + * See individual method javadocs for details. * <p> * [EMAIL PROTECTED] #equals} identifies all values with <code>NaN</code> in either real * or imaginary part - e.g., <pre> @@ -76,7 +76,7 @@ * <p> * Returns <code>NaN</code> if either real or imaginary part is * <code>NaN</code> and <code>Double.POSITIVE_INFINITY</code> if - * neither part is <code>NaN</code>, but at least on part takes an infinite + * neither part is <code>NaN</code>, but at least one part takes an infinite * value. * * @return the absolute value. @@ -110,11 +110,15 @@ * <p> * Uses the definitional formula * <pre> - * (a + bi) + (c + di) = (a+c) + (b + d)i + * (a + bi) + (c + di) = (a+c) + (b+d)i * </pre> * <p> - * Inifinite and NaN values are returned in the parts according to the - * rules for [EMAIL PROTECTED] java.lang.Double} arithmetic. + * If either this or <code>rhs</code> has a NaN value in either part, + * [EMAIL PROTECTED] #NaN} is returned; otherwise Inifinite and NaN values are + * returned in the parts of the result according to the rules for + * [EMAIL PROTECTED] java.lang.Double} arithmetic. + * <p> + * Throws <code>NullPointerException</code> if <code>rhs</code> is null. * * @param rhs the other complex number. * @return the complex number sum. @@ -128,13 +132,13 @@ * Return the conjugate of this complex number. The conjugate of * "A + Bi" is "A - Bi". * <p> - * Complex.NaN is returned if either the real or imaginary - * part of this Complex number equals Double.NaN. + * [EMAIL PROTECTED] #NaN} is returned if either the real or imaginary + * part of this Complex number equals <code>Double.NaN</code>. * <p> * If the imaginary part is infinite, and the real part is not NaN, * the returned value has infinite imaginary part of the opposite * sign - e.g. the conjugate of <code>1 + POSITIVE_INFINITY i</code> - * is <code>1 + NEGATIVE_INFINITY i</code> + * is <code>1 - NEGATIVE_INFINITY i</code> * * @return the conjugate of this Complex object */ @@ -152,7 +156,7 @@ * <pre><code> * a + bi ac + bd + (bc - ad)i * ----------- = ------------------------- - * c + di c*c + d*d + * c + di c<sup>2</sup> + d<sup>2</sup> * </code></pre> * but uses * <a href="http://doi.acm.org/10.1145/1039813.1039814"> @@ -172,9 +176,10 @@ * <code>rhs</code> is infinite (one or both parts infinite), * [EMAIL PROTECTED] #ZERO} is returned.</li> * <li>If this is infinite and <code>rhs</code> is finite, NaN values are - * returned in parts if the [EMAIL PROTECTED] java.lang.Double} rules applied to the - * definitional formula force NaN results.</li> + * returned in the parts of the result if the [EMAIL PROTECTED] java.lang.Double} + * rules applied to the definitional formula force NaN results.</li> * </ul> + * Throws <code>NullPointerException</code> if <code>rhs</code> is null. * * @param rhs the other complex number * @return the complex number quotient @@ -222,7 +227,7 @@ * <p> * All <code>NaN</code> values are considered to be equal - i.e, if either * (or both) real and imaginary parts of the complex number are equal - * to Double.NaN, the complex number is equal to + * to <code>Double.NaN</code>, the complex number is equal to * <code>Complex.NaN</code>. * * @param other Object to test for equality to this @@ -336,6 +341,8 @@ * (-INF + -INFi)(1 + NaNi) = NaN + NaNi * </code></pre> * + * Throws <code>NullPointerException</code> if <code>rhs</code> is null. + * * @param rhs the other complex number. * @return the complex number product. */ @@ -349,6 +356,9 @@ /** * Return the additive inverse of this complex number. + * <p> + * Returns <code>Complex.NaN</code> if either real or imaginary + * part of this Complex number equals <code>Double.NaN</code>. * * @return the negation of this complex number. */ @@ -363,7 +373,19 @@ /** * Return the difference between this complex number and the given complex * number. - * + * <p> + * Uses the definitional formula + * <pre> + * (a + bi) - (c + di) = (a-c) + (b-d)i + * </pre> + * <p> + * If either this or <code>rhs</code> has a NaN value in either part, + * [EMAIL PROTECTED] #NaN} is returned; otherwise inifinite and NaN values are + * returned in the parts of the result according to the rules for + * [EMAIL PROTECTED] java.lang.Double} arithmetic. + * <p> + * Throws <code>NullPointerException</code> if <code>rhs</code> is null. + * * @param rhs the other complex number. * @return the complex number difference. */ Modified: jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/ComplexUtils.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/ComplexUtils.java?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/ComplexUtils.java (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/src/java/org/apache/commons/math/complex/ComplexUtils.java Wed Nov 23 09:43:57 2005 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 The Apache Software Foundation. + * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,14 +19,20 @@ import org.apache.commons.math.util.MathUtils; /** - * Implementations of various transcendental functions for - * [EMAIL PROTECTED] org.apache.commons.math.complex.Complex} arguments. - * + * Static implementations of common + * [EMAIL PROTECTED] org.apache.commons.math.complex.Complex}-valued functions. Included + * are trigonometric, exponential, log, power and square root functions. + *<p> * Reference: * <ul> * <li><a href="http://myweb.lmu.edu/dmsmith/ZMLIB.pdf"> * Multiple Precision Complex Arithmetic and Functions</a></li> * </ul> + * See individual method javadocs for the computational formulas used. + * In general, NaN values in either real or imaginary parts of input arguments + * result in [EMAIL PROTECTED] Complex#NaN} returned. Otherwise, infinite or NaN values + * are returned as they arise in computing the real functions specified in the + * computational formulas. Null arguments result in NullPointerExceptions. * * @version $Revision$ $Date$ */ @@ -42,6 +48,15 @@ /** * Compute the <a href="http://mathworld.wolfram.com/InverseCosine.html"> * inverse cosine</a> for the given complex argument. + * <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. + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose inverse cosine is to be returned. * @return the inverse cosine of <code>z</code>. */ @@ -57,6 +72,15 @@ /** * Compute the <a href="http://mathworld.wolfram.com/InverseSine.html"> * inverse sine</a> for the given complex argument. + * <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. + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose inverse sine is to be returned. * @return the inverse sine of <code>z</code>. */ @@ -72,6 +96,15 @@ /** * Compute the <a href="http://mathworld.wolfram.com/InverseTangent.html"> * inverse tangent</a> for the given complex argument. + * <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. + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose inverse tangent is to be returned. * @return the inverse tangent of <code>z</code>. */ @@ -80,7 +113,6 @@ return Complex.NaN; } - return Complex.I.multiply( log(Complex.I.add(z).divide(Complex.I.subtract(z)))) .divide(new Complex(2.0, 0.0)); @@ -89,6 +121,26 @@ /** * Compute the <a href="http://mathworld.wolfram.com/Cosine.html">cosine</a> * for the given complex argument. + * <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> + * + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose cosine is to be returned. * @return the cosine of <code>z</code>. */ @@ -107,6 +159,26 @@ /** * Compute the <a href="http://mathworld.wolfram.com/HyperbolicCosine.html"> * hyperbolic cosine</a> for the given complex argument. + * <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> + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose hyperbolic cosine is to be returned. * @return the hyperbolic cosine of <code>z</code>. */ @@ -126,6 +198,27 @@ * Compute the * <a href="http://mathworld.wolfram.com/ExponentialFunction.html"> * exponential function</a> for the given complex argument. + * <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> + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value. * @return <i>e</i><sup><code>z</code></sup>. */ @@ -136,14 +229,34 @@ double b = z.getImaginary(); double expA = Math.exp(z.getReal()); - double sinB = Math.sin(b); - double cosB = Math.cos(b); - return new Complex(expA * cosB, expA * sinB); + return new Complex(expA * Math.cos(b), expA * Math.sin(b)); } /** * Compute the <a href="http://mathworld.wolfram.com/NaturalLogarithm.html"> * natural logarithm</a> for the given complex argument. + * <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 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 + * </code></pre> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value. * @return ln <code>z</code>. */ @@ -156,12 +269,56 @@ Math.atan2(z.getImaginary(), z.getReal())); } + /** + * Creates a complex number from the given polar representation. + * <p> + * The value returned is <code>r·e<sup>i·theta</sup></code>, computed as + * <code>r·cos(theta) + r·sin(theta)i</code> + * <p> + * If either <code>r</code> or <code>theta</code> is NaN, or + * <code>theta</code> is infinite, [EMAIL PROTECTED] Complex#NaN} is returned. + * <p> + * If <code>r</code> is infinite and <code>theta</code> is finite, + * infinite or NaN values may be returned in parts of the result, following + * the rules for double arithmetic.<pre> + * Examples: + * <code> + * polar2Complex(INFINITY, π/4) = INFINITY + INFINITY i + * polar2Complex(INFINITY, 0) = INFINITY + NaN i + * polar2Complex(INFINITY, -π/4) = INFINITY - INFINITY i + * polar2Complex(INFINITY, 5π/4) = -INFINITY - INFINITY i </code></pre> + * + * Throws <code>IllegalArgumentException</code> if <code>r < 0</code> + * + * @param r the modulus of the complex number to create + * @param theta the argument of the complex number to create + * @return <code>r·e<sup>i·theta</sup></code> + * @throws IllegalArgumentException if r is negative + */ + public static Complex polar2Complex(double r, double theta) { + if (r < 0) { + throw new IllegalArgumentException + ("Complex modulus must not be negative"); + } + return new Complex(r * Math.cos(theta), r * Math.sin(theta)); + } /** * Returns of value of <code>y</code> 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. + * <p> + * Throws <code>NullPointerException</code> if either x or y is null. + * * @param y the base. * @param x the exponent. - * @return <code>y</code><sup><code>z</code></sup>. + * @return <code>y</code><sup><code>x</code></sup> */ public static Complex pow(Complex y, Complex x) { return exp(x.multiply(log(y))); @@ -170,6 +327,26 @@ /** * Compute the <a href="http://mathworld.wolfram.com/Sine.html">sine</a> * for the given complex argument. + * <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> + * + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose sine is to be returned. * @return the sine of <code>z</code>. */ @@ -188,6 +365,26 @@ /** * Compute the <a href="http://mathworld.wolfram.com/HyperbolicSine.html"> * hyperbolic sine</a> for the given complex argument. + * <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> + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose hyperbolic sine is to be returned. * @return the hyperbolic sine of <code>z</code>. */ @@ -204,8 +401,36 @@ } /** - * Compute the <a href="http://mathworld.wolfram.com/SquareRoot.html">squre + * Compute the <a href="http://mathworld.wolfram.com/SquareRoot.html">square * root</a> for the given complex argument. + * <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> + * + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose square root is to be returned. * @return the square root of <code>z</code>. */ @@ -221,14 +446,26 @@ if (a >= 0.0) { return new Complex(t, b / (2.0 * t)); } else { - return new Complex(Math.abs(z.getImaginary()) / (2.0 * t), + return new Complex(Math.abs(b) / (2.0 * t), MathUtils.indicator(b) * t); } } /** - * Compute the <a href="http://mathworld.wolfram.com/SquareRoot.html">squre - * root of 1 - <code>z</code><sup>2</sup> for the given complex argument. + * Compute the <a href="http://mathworld.wolfram.com/SquareRoot.html">square + * root</a> of 1 - <code>z</code><sup>2</sup> for the given complex argument. + * <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. + * <p> + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value. * @return the square root of 1 - <code>z</code><sup>2</sup>. */ @@ -239,6 +476,26 @@ /** * Compute the <a href="http://mathworld.wolfram.com/Tangent.html"> * tangent</a> for the given complex argument. + * <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 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</code></pre> + * + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose tangent is to be returned. * @return the tangent of <code>z</code>. */ @@ -258,6 +515,26 @@ * Compute the * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html"> * hyperbolic tangent</a> for the given complex argument. + * <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> + * tan(1 ± INFINITY i) = NaN + NaN i + * tan(±INFINITY + i) = NaN + 0 i + * tan(±INFINITY ± INFINITY i) = NaN + NaN i</code></pre> + * + * Throws <code>NullPointerException</code> if z is null. + * * @param z the value whose hyperbolic tangent is to be returned. * @return the hyperbolic tangent of <code>z</code>. */ Modified: jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/TestUtils.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/TestUtils.java?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/TestUtils.java (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/TestUtils.java Wed Nov 23 09:43:57 2005 @@ -42,6 +42,10 @@ assertEquals(null, expected, actual, delta); } + /** + * Verifies that expected and actual are within delta, or are both NaN or + * infinities of the same sign. + */ public static void assertEquals(String msg, double expected, double actual, double delta) { // check for NaN if(Double.isNaN(expected)){ @@ -52,8 +56,26 @@ } } + /* + * Verifies that the two arguments are exactly the same, either + * both NaN or infinities of same sign, or identical floating point values. + */ + public static void assertSame(double expected, double actual) { + assertEquals(expected, actual, 0); + } + + /** + * Verifies that real and imaginary parts of the two complex arguments + * are exactly the same. Also ensures that NaN / infinite components match. + */ + public static void assertSame(Complex expected, Complex actual) { + assertSame(expected.getReal(), actual.getReal()); + assertSame(expected.getImaginary(), actual.getImaginary()); + } + /** - * + * Verifies that real and imaginary parts of the two complex arguments + * differ by at most delta. Also ensures that NaN / infinite components match. */ public static void assertEquals(Complex expected, Complex actual, double delta) { assertEquals(expected.getReal(), actual.getReal(), delta); Modified: jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexUtilsTest.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexUtilsTest.java?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexUtilsTest.java (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexUtilsTest.java Wed Nov 23 09:43:57 2005 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 The Apache Software Foundation. + * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,16 +25,63 @@ */ public class ComplexUtilsTest extends TestCase { + 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 negInfOne = new Complex(negInf, 1); + private Complex negInfInf = new Complex(negInf, inf); + private Complex infNegInf = new Complex(inf, negInf); + private Complex infInf = new Complex(inf, inf); + private Complex negInfNegInf = new Complex(negInf, negInf); + private Complex oneNaN = new Complex(1, nan); + private Complex infNaN = new Complex(inf, nan); + private Complex negInfNaN = new Complex(negInf, nan); + private Complex nanInf = new Complex(nan, inf); + private Complex nanNegInf = new Complex(nan, negInf); + private Complex zeroNaN = new Complex(0, nan); + private Complex nanZero = new Complex(nan, 0); + private Complex infZero = new Complex(inf, 0); + private Complex zeroInf = new Complex(0, inf); + + private ComplexFormat fmt = new ComplexFormat(); + public void testAcos() { Complex z = new Complex(3, 4); Complex expected = new Complex(0.936812, -2.30551); TestUtils.assertEquals(expected, ComplexUtils.acos(z), 1.0e-5); + TestUtils.assertEquals(new Complex(Math.acos(0), 0), + ComplexUtils.acos(Complex.ZERO), 1.0e-12); + } + + public void testAcosInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.acos(negInfNegInf)); } public void testAcosNaN() { assertTrue(ComplexUtils.acos(Complex.NaN).isNaN()); } + public void testAcosNull() { + try { + Complex z = ComplexUtils.acos(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testAsin() { Complex z = new Complex(3, 4); Complex expected = new Complex(0.633984, 2.30551); @@ -45,14 +92,55 @@ assertTrue(ComplexUtils.asin(Complex.NaN).isNaN()); } + public void testAsinInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.asin(negInfNegInf)); + } + + public void testAsinNull() { + try { + Complex z = ComplexUtils.asin(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testAtan() { Complex z = new Complex(3, 4); Complex expected = new Complex(1.44831, 0.158997); TestUtils.assertEquals(expected, ComplexUtils.atan(z), 1.0e-5); } + public void testAtanInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.atan(negInfNegInf)); + } + public void testAtanNaN() { assertTrue(ComplexUtils.atan(Complex.NaN).isNaN()); + assertTrue(ComplexUtils.atan(Complex.I).isNaN()); + } + + public void testAtanNull() { + try { + Complex z = ComplexUtils.atan(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } } public void testCos() { @@ -61,6 +149,30 @@ TestUtils.assertEquals(expected, ComplexUtils.cos(z), 1.0e-5); } + public void testCosNaN() { + assertTrue(ComplexUtils.cos(Complex.NaN).isNaN()); + } + + public void testCosInf() { + TestUtils.assertSame(infNegInf, ComplexUtils.cos(oneInf)); + TestUtils.assertSame(infInf, ComplexUtils.cos(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cos(negInfNegInf)); + } + + public void testCosNull() { + try { + Complex z = ComplexUtils.cos(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testCosh() { Complex z = new Complex(3, 4); Complex expected = new Complex(-6.58066, -7.58155); @@ -71,8 +183,24 @@ assertTrue(ComplexUtils.cosh(Complex.NaN).isNaN()); } - public void testCosNaN() { - assertTrue(ComplexUtils.cos(Complex.NaN).isNaN()); + public void testCoshInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(oneNegInf)); + TestUtils.assertSame(infInf, ComplexUtils.cosh(infOne)); + TestUtils.assertSame(infNegInf, ComplexUtils.cosh(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.cosh(negInfNegInf)); + } + + public void testCoshNull() { + try { + Complex z = ComplexUtils.cosh(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } } public void testExp() { @@ -85,6 +213,26 @@ assertTrue(ComplexUtils.exp(Complex.NaN).isNaN()); } + public void testExpInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(oneNegInf)); + TestUtils.assertSame(infInf, ComplexUtils.exp(infOne)); + TestUtils.assertSame(Complex.ZERO, ComplexUtils.exp(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.exp(negInfNegInf)); + } + + public void testExpNull() { + try { + Complex z = ComplexUtils.exp(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testLog() { Complex z = new Complex(3, 4); Complex expected = new Complex(1.60944, 0.927295); @@ -95,6 +243,97 @@ assertTrue(ComplexUtils.log(Complex.NaN).isNaN()); } + public void testLogInf() { + TestUtils.assertEquals(new Complex(inf, pi / 2), + ComplexUtils.log(oneInf), 10e-12); + TestUtils.assertEquals(new Complex(inf, -pi / 2), + ComplexUtils.log(oneNegInf), 10e-12); + TestUtils.assertEquals(infZero, ComplexUtils.log(infOne), 10e-12); + TestUtils.assertEquals(new Complex(inf, pi), + ComplexUtils.log(negInfOne), 10e-12); + TestUtils.assertEquals(new Complex(inf, pi / 4), + ComplexUtils.log(infInf), 10e-12); + TestUtils.assertEquals(new Complex(inf, -pi / 4), + ComplexUtils.log(infNegInf), 10e-12); + TestUtils.assertEquals(new Complex(inf, 3d * pi / 4), + ComplexUtils.log(negInfInf), 10e-12); + TestUtils.assertEquals(new Complex(inf, - 3d * pi / 4), + ComplexUtils.log(negInfNegInf), 10e-12); + } + + public void testlogNull() { + try { + Complex z = ComplexUtils.log(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + + public void testPolar2Complex() { + TestUtils.assertEquals(Complex.ONE, + ComplexUtils.polar2Complex(1, 0), 10e-12); + TestUtils.assertEquals(Complex.ZERO, + ComplexUtils.polar2Complex(0, 1), 10e-12); + TestUtils.assertEquals(Complex.ZERO, + ComplexUtils.polar2Complex(0, -1), 10e-12); + TestUtils.assertEquals(Complex.I, + ComplexUtils.polar2Complex(1, pi/2), 10e-12); + TestUtils.assertEquals(Complex.I.negate(), + ComplexUtils.polar2Complex(1, -pi/2), 10e-12); + double r = 0; + for (int i = 0; i < 5; i++) { + r += i; + double theta = 0; + for (int j =0; j < 20; j++) { + theta += pi / 6; + TestUtils.assertEquals(altPolar(r, theta), + ComplexUtils.polar2Complex(r, theta), 10e-12); + } + theta = -2 * pi; + for (int j =0; j < 20; j++) { + theta -= pi / 6; + TestUtils.assertEquals(altPolar(r, theta), + ComplexUtils.polar2Complex(r, theta), 10e-12); + } + } + } + + protected Complex altPolar(double r, double theta) { + return ComplexUtils.exp(Complex.I.multiply + (new Complex(theta, 0))).multiply(new Complex(r, 0)); + } + + public void testPolar2ComplexIllegalModulus() { + try { + Complex z = ComplexUtils.polar2Complex(-1, 0); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + } + + public void testPolar2ComplexNaN() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.polar2Complex(nan, 1)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.polar2Complex(1, nan)); + TestUtils.assertSame(Complex.NaN, + ComplexUtils.polar2Complex(nan, nan)); + } + + public void testPolar2ComplexInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.polar2Complex(1, inf)); + TestUtils.assertSame(Complex.NaN, + ComplexUtils.polar2Complex(1, negInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.polar2Complex(inf, inf)); + TestUtils.assertSame(Complex.NaN, + ComplexUtils.polar2Complex(inf, negInf)); + TestUtils.assertSame(infInf, ComplexUtils.polar2Complex(inf, pi/4)); + TestUtils.assertSame(infNaN, ComplexUtils.polar2Complex(inf, 0)); + TestUtils.assertSame(infNegInf, ComplexUtils.polar2Complex(inf, -pi/4)); + TestUtils.assertSame(negInfInf, ComplexUtils.polar2Complex(inf, 3*pi/4)); + TestUtils.assertSame(negInfNegInf, ComplexUtils.polar2Complex(inf, 5*pi/4)); + } + public void testPow() { Complex x = new Complex(3, 4); Complex y = new Complex(5, 6); @@ -112,12 +351,76 @@ assertTrue(ComplexUtils.pow(x, Complex.NaN).isNaN()); } + public void testPowInf() { + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, oneInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, oneNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, infOne)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, infInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, infNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, negInfInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(Complex.ONE, negInfNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infOne, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfOne, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infInf, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infNegInf, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfInf, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfNegInf, Complex.ONE)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfNegInf, infNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfNegInf, negInfNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(negInfNegInf, infInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infInf, infNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infInf, negInfNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infInf, infInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infNegInf, infNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infNegInf, negInfNegInf)); + TestUtils.assertSame(Complex.NaN,ComplexUtils.pow(infNegInf, infInf)); + } + + public void testpowNull() { + try { + Complex z = ComplexUtils.pow(null, Complex.ONE); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + try { + Complex z = ComplexUtils.pow(Complex.ONE, 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, ComplexUtils.sin(z), 1.0e-5); } + public void testSinInf() { + TestUtils.assertSame(infInf, ComplexUtils.sin(oneInf)); + TestUtils.assertSame(infNegInf, ComplexUtils.sin(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sin(negInfNegInf)); + } + + public void testSinNaN() { + assertTrue(ComplexUtils.sin(Complex.NaN).isNaN()); + } + + public void testSinNull() { + try { + Complex z = ComplexUtils.sin(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testSinh() { Complex z = new Complex(3, 4); Complex expected = new Complex(-6.54812, -7.61923); @@ -128,8 +431,24 @@ assertTrue(ComplexUtils.sinh(Complex.NaN).isNaN()); } - public void testSinNaN() { - assertTrue(ComplexUtils.sin(Complex.NaN).isNaN()); + public void testSinhInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(oneNegInf)); + TestUtils.assertSame(infInf, ComplexUtils.sinh(infOne)); + TestUtils.assertSame(negInfInf, ComplexUtils.sinh(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.sinh(negInfNegInf)); + } + + public void testsinhNull() { + try { + Complex z = ComplexUtils.sinh(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } } public void testSqrtRealPositive() { @@ -161,6 +480,44 @@ Complex expected = new Complex(1.0, -2.0); TestUtils.assertEquals(expected, ComplexUtils.sqrt(z), 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, ComplexUtils.sqrt(z), 10e-12); + } + } + } + + public void testSqrtNaN() { + assertTrue(ComplexUtils.sqrt(Complex.NaN).isNaN()); + } + + public void testSqrtInf() { + TestUtils.assertSame(infNaN, ComplexUtils.sqrt(oneInf)); + TestUtils.assertSame(infNaN, ComplexUtils.sqrt(oneNegInf)); + TestUtils.assertSame(infZero, ComplexUtils.sqrt(infOne)); + TestUtils.assertSame(zeroInf, ComplexUtils.sqrt(negInfOne)); + TestUtils.assertSame(infNaN, ComplexUtils.sqrt(infInf)); + TestUtils.assertSame(infNaN, ComplexUtils.sqrt(infNegInf)); + TestUtils.assertSame(nanInf, ComplexUtils.sqrt(negInfInf)); + TestUtils.assertSame(nanNegInf, ComplexUtils.sqrt(negInfNegInf)); + } + + public void testSqrtNull() { + try { + Complex z = ComplexUtils.sqrt(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } public void testSqrt1z() { Complex z = new Complex(3, 4); @@ -172,8 +529,13 @@ assertTrue(ComplexUtils.sqrt1z(Complex.NaN).isNaN()); } - public void testSqrtNaN() { - assertTrue(ComplexUtils.sqrt(Complex.NaN).isNaN()); + public void testSqrt1zNull() { + try { + Complex z = ComplexUtils.sqrt1z(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } } public void testTan() { @@ -182,6 +544,30 @@ TestUtils.assertEquals(expected, ComplexUtils.tan(z), 1.0e-5); } + public void testTanNaN() { + assertTrue(ComplexUtils.tan(Complex.NaN).isNaN()); + } + + public void testTanInf() { + TestUtils.assertSame(zeroNaN, ComplexUtils.tan(oneInf)); + TestUtils.assertSame(zeroNaN, ComplexUtils.tan(oneNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(infOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tan(negInfNegInf)); + } + + public void testTanNull() { + try { + Complex z = ComplexUtils.tan(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } + } + public void testTanh() { Complex z = new Complex(3, 4); Complex expected = new Complex(1.00071, 0.00490826); @@ -192,7 +578,23 @@ assertTrue(ComplexUtils.tanh(Complex.NaN).isNaN()); } - public void testTanNaN() { - assertTrue(ComplexUtils.tan(Complex.NaN).isNaN()); + public void testTanhInf() { + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(oneInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(oneNegInf)); + TestUtils.assertSame(nanZero, ComplexUtils.tanh(infOne)); + TestUtils.assertSame(nanZero, ComplexUtils.tanh(negInfOne)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(infInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(infNegInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(negInfInf)); + TestUtils.assertSame(Complex.NaN, ComplexUtils.tanh(negInfNegInf)); + } + + public void testTanhNull() { + try { + Complex z = ComplexUtils.tanh(null); + fail("Expecting NullPointerException"); + } catch (NullPointerException ex) { + // expected + } } } Modified: jakarta/commons/proper/math/branches/MATH_1_1/xdocs/changes.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/xdocs/changes.xml?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/xdocs/changes.xml (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/xdocs/changes.xml Wed Nov 23 09:43:57 2005 @@ -38,13 +38,21 @@ Commons Math Release Notes</title> </properties> <body> - <release version="1.1-RC3" date="TBD" + <release version="1.1-RC4" date="TBD" description="This is a maintenance release containing bug fixes and enhancements. All API changes are binary compatible with version 1.0. The enhancements include some new probability distributions, a Fraction class, new matrix and numerical utilities, and a PRNG pluggability framework making it possible to replace the JDK-supplied random number generator in commons-math (and elsewhere) with alternative PRNG implementations."> + <action dev="psteitz" type="update"> + Added polar2Complex method to ComplexUtils to create Complex numbers + from polar representations. + </action> + <action dev="psteitz" type="fix" issue="37086"> + Improved documentation and test cases related to handling of infinite + and NaN values in Complex, ComplexUtils classes. + </action> <action dev="psteitz" type="fix" issue="37019" due-to="Mauro Talevi"> Fixed incorrect NaN handling in o.a.m.s.d.rank.Min, Max </action> Modified: jakarta/commons/proper/math/branches/MATH_1_1/xdocs/userguide/complex.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/xdocs/userguide/complex.xml?rev=348502&r1=348501&r2=348502&view=diff ============================================================================== --- jakarta/commons/proper/math/branches/MATH_1_1/xdocs/userguide/complex.xml (original) +++ jakarta/commons/proper/math/branches/MATH_1_1/xdocs/userguide/complex.xml Wed Nov 23 09:43:57 2005 @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright 2003-2004 The Apache Software Foundation + Copyright 2003-2005 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ <!-- $Revision$ $Date$ --> <document url="stat.html"> <properties> - <title>The Commons Math User Guide - Statistics</title> + <title>The Commons Math User Guide - Complex Numbers</title> </properties> <body> <section name="7 Complex Numbers"> @@ -37,6 +37,18 @@ org.apache.commons.math.complex.Complex</a> provides a complex number type that forms the basis for the complex functionality found in commons-math. + </p> + <p> + Complex functions and arithmetic operations are implemented in + commons-math by applying standard computational formulas and + following the rules for <code>java.lang.Double</code> arithmetic in + handling infinite and <code>NaN</code> values. No attempt is made + to comply with ANSII/IEC C99x Annex G or any other standard for + Complex arithmetic. See the class and method javadocs for the + <a href="../apidocs/org/apache/commons/math/complex/Complex.html"> + Complex</a> and + <a href="../apidocs/org/apache/commons/math/complex/ComplexUtils.html"> + ComplexUtils</a> classes for details on computing formulas. </p> <p> To create a complex number, simply call the constructor passing in two @@ -45,9 +57,14 @@ <source>Complex c = new Complex(1.0, 3.0); // 1 + 3i</source> </p> <p> - The <code>Complex</code> class provides many unary and binary + Complex numbers may also be created from polar representations + using the <code>polar2Complex</code> method in + <code>ComplexUtils</code>. + </p> + <p> + The <code>Complex</code> class provides basic unary and binary complex number operations. These operations provide the means to add, - subtract, multiple and, divide complex numbers along with other + subtract, multiply and divide complex numbers along with other complex number functions similar to the real number functions found in <code>java.math.BigDecimal</code>: <source>Complex lhs = new Complex(1.0, 3.0); @@ -62,7 +79,7 @@ <subsection name="7.3 Complex Transcendental Functions" href="function"> <p> <a href="../apidocs/org/apache/commons/math/complex/ComplexUtils.html"> - org.apache.commons.math.complex.ComplexMath</a> provides + org.apache.commons.math.complex.ComplexUtils</a> provides implementations of serveral transcendental functions involving complex number arguments. These operations provide the means to compute the log, sine, tangent and, other complex values similar to the real --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]