Author: psteitz
Date: Mon Jan  5 19:46:29 2009
New Revision: 731822

URL: http://svn.apache.org/viewvc?rev=731822&view=rev
Log:
Changed return type of nthRoot to List
Renamed getPhi to getArgument
Changed and documented behavior of nthRoot wrt NaN, infinite components
Improved nth root computation
Added some test cases

Modified:
    
commons/proper/math/trunk/src/java/org/apache/commons/math/complex/Complex.java
    
commons/proper/math/trunk/src/test/org/apache/commons/math/complex/ComplexTest.java

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=731822&r1=731821&r2=731822&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 
Mon Jan  5 19:46:29 2009
@@ -19,7 +19,7 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.List;
 
 import org.apache.commons.math.MathRuntimeException;
 import org.apache.commons.math.util.MathUtils;
@@ -867,50 +867,76 @@
     
     
     /**
-     * Compute the angle phi of this complex number.
-     * @return the angle phi of this complex number
+     * <p>Compute the argument of this complex number.
+     * </p>
+     * <p>The argument is the angle phi between the positive real axis and the 
point
+     * representing this number in the complex plane. The value returned is 
between -PI (not inclusive) 
+     * and PI (inclusive), with negative values returned for numbers with 
negative imaginary parts.
+     * </p>
+     * <p>If either real or imaginary part (or both) is NaN, NaN is returned.  
Infinite parts are handled
+     * as java.Math.atan2 handles them, essentially treating finite parts as 
zero in the presence of
+     * an infinite coordinate and returning a multiple of pi/4 depending on 
the signs of the infinite
+     * parts.  See the javadoc for java.Math.atan2 for full details.</p>
+     * 
+     * @return the argument of this complex number
      */
-    public double getPhi() {
+    public double getArgument() {
         return Math.atan2(getImaginary(), getReal());
     }
     
     /**
-     * Compute the n-th root of this complex number.
-     * <p>
-     * For a given n it implements the formula: <pre>
-     * <code> z_k = pow( abs , 1.0/n ) * (cos(phi + k * 2&pi;) + i * (sin(phi 
+ k * 2&pi;)</code></pre></p>
-     * with <i><code>k=0, 1, ..., n-1</code></i> and <i><code>pow(abs, 1.0 / 
n)</code></i> is the nth root of the absolute-value.
-     * <p>
+     * <p>Computes the n-th roots of this complex number.
+     * </p>
+     * <p>The nth roots are defined by the formula: <pre>
+     * <code> z<sub>k</sub> = abs<sup> 1/n</sup> (cos(phi + 2&pi;k/n) + i 
(sin(phi + 2&pi;k/n))</code></pre>
+     * for <i><code>k=0, 1, ..., n-1</code></i>, where <code>abs</code> and 
<code>phi</code> are
+     * respectively the {...@link #abs() modulus} and {...@link #getArgument() 
argument} of this complex number.
+     * </p>
+     * <p>If one or both parts of this complex number is NaN, a list with just 
one element,
+     *  {...@link #NaN} is returned.</p>
+     * <p>if neither part is NaN, but at least one part is infinite, the 
result is a one-element
+     * list containing {...@link #INF}.</p>
      * 
      * @param n degree of root
-     * @return Collection<Complex> all nth roots of this complex number as a 
Collection
-     * @throws IllegalArgumentException if parameter n is negative
+     * @return List<Complex> all nth roots of this complex number
+     * @throws IllegalArgumentException if parameter n is less than or equal 
to 0
      * @since 2.0
      */
-    public Collection<Complex> nthRoot(int n) throws IllegalArgumentException {
+    public List<Complex> nthRoot(int n) throws IllegalArgumentException {
 
         if (n <= 0) {
             throw MathRuntimeException.createIllegalArgumentException("cannot 
compute nth root for null or negative n: {0}",
                     new Object[] { n });
         }
+        
+        List<Complex> result = new ArrayList<Complex>();
+        
+        if (isNaN()) {
+            result.add(Complex.NaN);
+            return result;
+        }
+        
+        if (isInfinite()) {
+            result.add(Complex.INF);
+            return result;
+        }
 
-        Collection<Complex> result = new ArrayList<Complex>();
-
-        // nth root of abs
+        // nth root of abs -- faster / more accurate to use a solver here?
         final double nthRootOfAbs = Math.pow(abs(), 1.0 / n);
 
         // Compute nth roots of complex number with k = 0, 1, ... n-1
-        final double phi = getPhi();
+        final double nthPhi = getArgument()/n;
+        final double slice = 2 * Math.PI / n;
+        double innerPart = nthPhi;
         for (int k = 0; k < n ; k++) {
             // inner part
-            final double innerPart     = (phi + k * 2 * Math.PI) / n;
             final double realPart      = nthRootOfAbs *  Math.cos(innerPart);
             final double imaginaryPart = nthRootOfAbs *  Math.sin(innerPart);
             result.add(createComplex(realPart, imaginaryPart));
+            innerPart += slice;
         }
 
         return result;
-
     }
 
     /**

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=731822&r1=731821&r2=731822&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
 Mon Jan  5 19:46:29 2009
@@ -19,6 +19,8 @@
 
 import org.apache.commons.math.TestUtils;
 
+import java.util.List;
+
 import junit.framework.TestCase;
 
 /**
@@ -801,7 +803,7 @@
      * </code>
      * </pre>
      */
-    public void testNthRoot_cornercase_thirdRoot_realPartEmpty() {
+    public void testNthRoot_cornercase_thirdRoot_realPartZero() {
         // complex number with only imaginary part
         Complex z = new Complex(0,2);
         // The List holding all third roots
@@ -823,26 +825,82 @@
      * Test cornercases with NaN and Infinity.
      */
     public void testNthRoot_cornercase_NAN_Inf() {
-        // third root of z = 1 + NaN * i
-        for (Complex c : oneNaN.nthRoot(3)) {
-            // both parts should be nan
-            assertEquals(nan, c.getReal());
-            assertEquals(nan, c.getImaginary());
-        }
-        // third root of z = inf + NaN * i
-        for (Complex c : infNaN.nthRoot(3)) {
-            // both parts should be nan
-            assertEquals(nan, c.getReal());
-            assertEquals(nan, c.getImaginary());
-        }
-        // third root of z = neginf + 1 * i
-        Complex[] zInfOne = negInfOne.nthRoot(2).toArray(new Complex[0]);
-        // first root
-        assertEquals(inf, zInfOne[0].getReal());
-        assertEquals(inf, zInfOne[0].getImaginary());
-        // second root
-        assertEquals(neginf, zInfOne[1].getReal());
-        assertEquals(neginf, zInfOne[1].getImaginary());
+        // NaN + finite -> NaN
+        List<Complex> roots = oneNaN.nthRoot(3);
+        assertEquals(1,roots.size());
+        assertEquals(Complex.NaN, roots.get(0));
+        
+        roots = nanZero.nthRoot(3);
+        assertEquals(1,roots.size());
+        assertEquals(Complex.NaN, roots.get(0));
+        
+        // NaN + infinite -> NaN
+        roots = nanInf.nthRoot(3);
+        assertEquals(1,roots.size());
+        assertEquals(Complex.NaN, roots.get(0));
+        
+        // finite + infinite -> Inf
+        roots = oneInf.nthRoot(3);
+        assertEquals(1,roots.size());
+        assertEquals(Complex.INF, roots.get(0));
+        
+        // infinite + infinite -> Inf
+        roots = negInfInf.nthRoot(3);
+        assertEquals(1,roots.size());
+        assertEquals(Complex.INF, roots.get(0));
+    }
+    
+    /**
+     * Test standard values
+     */
+    public void testGetArgument() {
+        Complex z = new Complex(1, 0);
+        assertEquals(0.0, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(1, 1);
+        assertEquals(Math.PI/4, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(0, 1);
+        assertEquals(Math.PI/2, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(-1, 1);
+        assertEquals(3 * Math.PI/4, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(-1, 0);
+        assertEquals(Math.PI, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(-1, -1);
+        assertEquals(-3 * Math.PI/4, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(0, -1);
+        assertEquals(-Math.PI/2, z.getArgument(), 1.0e-12);
+        
+        z = new Complex(1, -1);
+        assertEquals(-Math.PI/4, z.getArgument(), 1.0e-12);
+        
+    }
+    
+    /**
+     * Verify atan2-style handling of infinite parts
+     */
+    public void testGetArgumentInf() {
+        assertEquals(Math.PI/4, infInf.getArgument(), 1.0e-12);
+        assertEquals(Math.PI/2, oneInf.getArgument(), 1.0e-12);
+        assertEquals(0.0, infOne.getArgument(), 1.0e-12);
+        assertEquals(Math.PI/2, zeroInf.getArgument(), 1.0e-12);
+        assertEquals(0.0, infZero.getArgument(), 1.0e-12);
+        assertEquals(Math.PI, negInfOne.getArgument(), 1.0e-12);
+        assertEquals(-3.0*Math.PI/4, negInfNegInf.getArgument(), 1.0e-12);  
+        assertEquals(-Math.PI/2, oneNegInf.getArgument(), 1.0e-12);        
+    }
+    
+    /**
+     * Verify that either part NaN results in NaN
+     */
+    public void testGetArgumentNaN() {
+        assertEquals(nan, nanZero.getArgument());
+        assertEquals(nan, zeroNaN.getArgument());
+        assertEquals(nan, Complex.NaN.getArgument());  
     }
 
 }


Reply via email to