added nth root computation for complex numbers
JIRA: MATH-236 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@729639 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9eccfc3c46
commit
c4126f3174
3
pom.xml
3
pom.xml
|
@ -117,6 +117,9 @@
|
|||
<contributor>
|
||||
<name>Ken Geis</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Bernhard Grünewaldt</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Elliotte Rusty Harold</name>
|
||||
</contributor>
|
||||
|
|
|
@ -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}\"" },
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* For a given n it implements the formula: <pre>
|
||||
* <code> z_k = pow( abs , 1.0/n ) * (cos(phi + k * 2π) + i * (sin(phi + k * 2π)</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>
|
||||
*
|
||||
* @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
|
||||
* @since 2.0
|
||||
*/
|
||||
public Collection<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 });
|
||||
}
|
||||
|
||||
Collection<Complex> result = new ArrayList<Complex>();
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -39,6 +39,9 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
</properties>
|
||||
<body>
|
||||
<release version="2.0" date="TBD" description="TBD">
|
||||
<action dev="luc" type="add" issue="MATH-236" due-to="Bernhard Grünewaldt">
|
||||
Added nth root computation for complex numbers.
|
||||
</action>
|
||||
<action dev="luc" type="add" issue="MATH-230" due-to="Sujit Pal and Ismael Juma">
|
||||
Added support for sparse matrix.
|
||||
</action>
|
||||
|
|
|
@ -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 <b>third roots</b> of z.
|
||||
* <pre>
|
||||
* <code>
|
||||
* <b>z = -2 + 2 * i</b>
|
||||
* => z_0 = 1 + i
|
||||
* => z_1 = -1.3660 + 0.3660 * i
|
||||
* => z_2 = 0.3660 - 1.3660 * i
|
||||
* </code>
|
||||
* </pre>
|
||||
*/
|
||||
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 <b>fourth roots</b> of z.
|
||||
* <pre>
|
||||
* <code>
|
||||
* <b>z = 5 - 2 * i</b>
|
||||
* => 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
|
||||
* </code>
|
||||
* </pre>
|
||||
*/
|
||||
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 <b>third roots</b> of z.
|
||||
* <pre>
|
||||
* <code>
|
||||
* <b>z = 8</b>
|
||||
* => z_0 = 2
|
||||
* => z_1 = -1 + 1.73205 * i
|
||||
* => z_2 = -1 - 1.73205 * i
|
||||
* </code>
|
||||
* </pre>
|
||||
*/
|
||||
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 <b>third roots</b> of z with real part 0.
|
||||
* <pre>
|
||||
* <code>
|
||||
* <b>z = 2 * i</b>
|
||||
* => z_0 = 1.0911 + 0.6299 * i
|
||||
* => z_1 = -1.0911 + 0.6299 * i
|
||||
* => z_2 = -2.3144 - 1.2599 * i
|
||||
* </code>
|
||||
* </pre>
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue