diff --git a/pom.xml b/pom.xml index e50df2047..f4ed80efe 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,9 @@ Ken Geis + + Bernhard Grünewaldt + Elliotte Rusty Harold diff --git a/src/java/org/apache/commons/math/MessagesResources_fr.java b/src/java/org/apache/commons/math/MessagesResources_fr.java index 90aa88564..7d6646ca1 100644 --- a/src/java/org/apache/commons/math/MessagesResources_fr.java +++ b/src/java/org/apache/commons/math/MessagesResources_fr.java @@ -233,6 +233,10 @@ public class MessagesResources_fr { "URL {0} contains no data", "l''adresse {0} ne contient aucune donn\u00e9e" }, + // org.apache.commons.math.complex.Complex + { "cannot compute nth root for null or negative n: {0}", + "impossible de calculer la racine ni\u00e8me pour n n\u00e9gatif ou nul : {0}" }, + // org.apache.commons.math.complex.ComplexFormat { "unparseable complex number: \"{0}\"", "\u00e9chec d''analyse du nombre complexe \"{0}\"" }, diff --git a/src/java/org/apache/commons/math/complex/Complex.java b/src/java/org/apache/commons/math/complex/Complex.java index 8b622cb29..df2ee1f3f 100644 --- a/src/java/org/apache/commons/math/complex/Complex.java +++ b/src/java/org/apache/commons/math/complex/Complex.java @@ -18,6 +18,10 @@ package org.apache.commons.math.complex; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.commons.math.MathRuntimeException; import org.apache.commons.math.util.MathUtils; /** @@ -859,6 +863,55 @@ public class Complex implements Serializable { return createComplex(MathUtils.sinh(real2) / d, Math.sin(imaginary2) / d); } + + + + /** + * Compute the angle phi of this complex number. + * @return the angle phi of this complex number + */ + public double getPhi() { + return Math.atan2(getImaginary(), getReal()); + } + + /** + * Compute the n-th root of this complex number. + *

+ * For a given n it implements the formula:

+     *  z_k = pow( abs , 1.0/n ) * (cos(phi + k * 2π) + i * (sin(phi + k * 2π)

+ * with k=0, 1, ..., n-1 and pow(abs, 1.0 / n) is the nth root of the absolute-value. + *

+ * + * @param n degree of root + * @return Collection all nth roots of this complex number as a Collection + * @throws IllegalArgumentException if parameter n is negative + * @since 2.0 + */ + public Collection nthRoot(int n) throws IllegalArgumentException { + + if (n <= 0) { + throw MathRuntimeException.createIllegalArgumentException("cannot compute nth root for null or negative n: {0}", + new Object[] { n }); + } + + Collection result = new ArrayList(); + + // nth root of abs + 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(); + 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)); + } + + return result; + + } /** * Create a complex number given the real and imaginary parts. diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index 5b8398493..cf4108383 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,6 +39,9 @@ The type attribute can be add,update,fix,remove. + + Added nth root computation for complex numbers. + Added support for sparse matrix. diff --git a/src/test/org/apache/commons/math/complex/ComplexTest.java b/src/test/org/apache/commons/math/complex/ComplexTest.java index 61ff86f52..48d130c89 100644 --- a/src/test/org/apache/commons/math/complex/ComplexTest.java +++ b/src/test/org/apache/commons/math/complex/ComplexTest.java @@ -695,5 +695,154 @@ public class ComplexTest extends TestCase { public void testMath221() { assertEquals(new Complex(0,-1), new Complex(0,1).multiply(new Complex(-1,0))); } + + /** + * Test: computing third roots of z. + *

+     * 
+     * z = -2 + 2 * i
+     *   => z_0 =  1      +          i
+     *   => z_1 = -1.3660 + 0.3660 * i
+     *   => z_2 =  0.3660 - 1.3660 * i
+     * 
+     * 
+ */ + public void testNthRoot_normal_thirdRoot() { + // The complex number we want to compute all third-roots for. + Complex z = new Complex(-2,2); + // The List holding all third roots + Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]); + // Returned Collection must not be empty! + assertEquals(3, thirdRootsOfZ.length); + // test z_0 + assertEquals(1.0, thirdRootsOfZ[0].getReal(), 1.0e-5); + assertEquals(1.0, thirdRootsOfZ[0].getImaginary(), 1.0e-5); + // test z_1 + assertEquals(-1.3660254037844386, thirdRootsOfZ[1].getReal(), 1.0e-5); + assertEquals(0.36602540378443843, thirdRootsOfZ[1].getImaginary(), 1.0e-5); + // test z_2 + assertEquals(0.366025403784439, thirdRootsOfZ[2].getReal(), 1.0e-5); + assertEquals(-1.3660254037844384, thirdRootsOfZ[2].getImaginary(), 1.0e-5); + } + + + /** + * Test: computing fourth roots of z. + *
+     * 
+     * z = 5 - 2 * i
+     *   => z_0 =  1.5164 - 0.1446 * i
+     *   => z_1 =  0.1446 + 1.5164 * i
+     *   => z_2 = -1.5164 + 0.1446 * i
+     *   => z_3 = -1.5164 - 0.1446 * i
+     * 
+     * 
+ */ + public void testNthRoot_normal_fourthRoot() { + // The complex number we want to compute all third-roots for. + Complex z = new Complex(5,-2); + // The List holding all fourth roots + Complex[] fourthRootsOfZ = z.nthRoot(4).toArray(new Complex[0]); + // Returned Collection must not be empty! + assertEquals(4, fourthRootsOfZ.length); + // test z_0 + assertEquals(1.5164629308487783, fourthRootsOfZ[0].getReal(), 1.0e-5); + assertEquals(-0.14469266210702247, fourthRootsOfZ[0].getImaginary(), 1.0e-5); + // test z_1 + assertEquals(0.14469266210702256, fourthRootsOfZ[1].getReal(), 1.0e-5); + assertEquals(1.5164629308487783, fourthRootsOfZ[1].getImaginary(), 1.0e-5); + // test z_2 + assertEquals(-1.5164629308487783, fourthRootsOfZ[2].getReal(), 1.0e-5); + assertEquals(0.14469266210702267, fourthRootsOfZ[2].getImaginary(), 1.0e-5); + // test z_3 + assertEquals(-0.14469266210702275, fourthRootsOfZ[3].getReal(), 1.0e-5); + assertEquals(-1.5164629308487783, fourthRootsOfZ[3].getImaginary(), 1.0e-5); + } + + /** + * Test: computing third roots of z. + *
+     * 
+     * z = 8
+     *   => z_0 =  2
+     *   => z_1 = -1 + 1.73205 * i
+     *   => z_2 = -1 - 1.73205 * i
+     * 
+     * 
+ */ + public void testNthRoot_cornercase_thirdRoot_imaginaryPartEmpty() { + // The number 8 has three third roots. One we all already know is the number 2. + // But there are two more complex roots. + Complex z = new Complex(8,0); + // The List holding all third roots + Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]); + // Returned Collection must not be empty! + assertEquals(3, thirdRootsOfZ.length); + // test z_0 + assertEquals(2.0, thirdRootsOfZ[0].getReal(), 1.0e-5); + assertEquals(0.0, thirdRootsOfZ[0].getImaginary(), 1.0e-5); + // test z_1 + assertEquals(-1.0, thirdRootsOfZ[1].getReal(), 1.0e-5); + assertEquals(1.7320508075688774, thirdRootsOfZ[1].getImaginary(), 1.0e-5); + // test z_2 + assertEquals(-1.0, thirdRootsOfZ[2].getReal(), 1.0e-5); + assertEquals(-1.732050807568877, thirdRootsOfZ[2].getImaginary(), 1.0e-5); + } + + + /** + * Test: computing third roots of z with real part 0. + *
+     * 
+     * z = 2 * i
+     *   => z_0 =  1.0911 + 0.6299 * i
+     *   => z_1 = -1.0911 + 0.6299 * i
+     *   => z_2 = -2.3144 - 1.2599 * i
+     * 
+     * 
+ */ + public void testNthRoot_cornercase_thirdRoot_realPartEmpty() { + // complex number with only imaginary part + Complex z = new Complex(0,2); + // The List holding all third roots + Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]); + // Returned Collection must not be empty! + assertEquals(3, thirdRootsOfZ.length); + // test z_0 + assertEquals(1.0911236359717216, thirdRootsOfZ[0].getReal(), 1.0e-5); + assertEquals(0.6299605249474365, thirdRootsOfZ[0].getImaginary(), 1.0e-5); + // test z_1 + assertEquals(-1.0911236359717216, thirdRootsOfZ[1].getReal(), 1.0e-5); + assertEquals(0.6299605249474365, thirdRootsOfZ[1].getImaginary(), 1.0e-5); + // test z_2 + assertEquals(-2.3144374213981936E-16, thirdRootsOfZ[2].getReal(), 1.0e-5); + assertEquals(-1.2599210498948732, thirdRootsOfZ[2].getImaginary(), 1.0e-5); + } + + /** + * 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()); + } }