You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ps...@apache.org on 2005/11/06 19:07:11 UTC
svn commit: r331126 - in /jakarta/commons/proper/math/branches/MATH_1_1/src:
java/org/apache/commons/math/complex/Complex.java
test/org/apache/commons/math/complex/ComplexTest.java
Author: psteitz
Date: Sun Nov 6 10:06:46 2005
New Revision: 331126
URL: http://svn.apache.org/viewcvs?rev=331126&view=rev
Log:
Improved consistency, documentation and test cases for Complex arithemetic.
PR# 37086
Modified:
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/test/org/apache/commons/math/complex/ComplexTest.java
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=331126&r1=331125&r2=331126&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 Sun Nov 6 10:06:46 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.
@@ -22,6 +22,16 @@
/**
* 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
+ * infinite values according to the rules for {@link 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.
+ * <p>
+ * {@link #equals} identifies all values with <code>NaN</code> in either real
+ * or imaginary part - e.g., <pre>
+ * <code>1 + NaNi == NaN + i == NaN + NaNi.</code></pre>
*
* @author Apache Software Foundation
* @version $Revision$ $Date$
@@ -40,6 +50,9 @@
/** A complex number representing "1.0 + 0.0i" */
public static final Complex ONE = new Complex(1.0, 0.0);
+ /** A complex number representing "0.0 + 0.0i" */
+ public static final Complex ZERO = new Complex(0.0, 0.0);
+
/** The imaginary part. */
protected double imaginary;
@@ -60,6 +73,11 @@
/**
* Return the absolute value of this complex number.
+ * <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
+ * value.
*
* @return the absolute value.
*/
@@ -67,6 +85,11 @@
if (isNaN()) {
return Double.NaN;
}
+
+ if (isInfinite()) {
+ return Double.POSITIVE_INFINITY;
+ }
+
if (Math.abs(real) < Math.abs(imaginary)) {
if (imaginary == 0.0) {
return Math.abs(real);
@@ -84,38 +107,77 @@
/**
* Return the sum of 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>
+ * Inifinite and NaN values are returned in the parts according to the
+ * rules for {@link java.lang.Double} arithmetic.
*
* @param rhs the other complex number.
* @return the complex number sum.
*/
- public Complex add(Complex rhs) {
- if (isNaN() || rhs.isNaN()) {
- return NaN;
- }
-
+ public Complex add(Complex rhs) {
return new Complex(real + rhs.getReal(),
imaginary + rhs.getImaginary());
}
/**
- * Return the conjugate of this complex number. The conjugate of
- * "A + Bi" is "A - Bi". Complex.NaN is returned if either the real or imaginary part of
- * this Complex number equals Double.NaN.
+ * 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.
+ * <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>
*
* @return the conjugate of this Complex object
*/
public Complex conjugate() {
if (isNaN()) {
return NaN;
- }
-
+ }
return new Complex(real, -imaginary);
}
/**
* Return the quotient of this complex number and the given complex number.
- * @param rhs the other complex number.
- * @return the complex number quotient.
+ * <p>
+ * Implements the definitional formula
+ * <pre><code>
+ * a + bi ac + bd + (bc - ad)i
+ * ----------- = -------------------------
+ * c + di c*c + d*d
+ * </code></pre>
+ * but uses
+ * <a href="http://doi.acm.org/10.1145/1039813.1039814">
+ * prescaling of operands</a> to limit the effects of overflows and
+ * underflows in the computation.
+ * <p>
+ * Infinite and NaN values are handled / returned according to the
+ * following rules, applied in the order presented:
+ * <ul>
+ * <li>If either this or <code>rhs</code> has a NaN value in either part,
+ * {@link #NaN} is returned.</li>
+ * <li>If <code>rhs</code> equals {@link #ZERO}, {@link #NaN} is returned.
+ * </li>
+ * <li>If this and <code>rhs</code> are both infinite,
+ * {@link #NaN} is returned.</li>
+ * <li>If this is finite (i.e., has no infinite or NaN parts) and
+ * <code>rhs</code> is infinite (one or both parts infinite),
+ * {@link #ZERO} is returned.</li>
+ * <li>If this is infinite and <code>rhs</code> is finite, NaN values are
+ * returned in parts if the {@link java.lang.Double} rules applied to the
+ * definitional formula force NaN results.</li>
+ * </ul>
+ *
+ * @param rhs the other complex number
+ * @return the complex number quotient
*/
public Complex divide(Complex rhs) {
if (isNaN() || rhs.isNaN()) {
@@ -125,7 +187,11 @@
double c = rhs.getReal();
double d = rhs.getImaginary();
if (c == 0.0 && d == 0.0) {
- throw new ArithmeticException("Error: division by zero.");
+ return NaN;
+ }
+
+ if (rhs.isInfinite() && !isInfinite()) {
+ return ZERO;
}
if (Math.abs(c) < Math.abs(d)) {
@@ -162,7 +228,7 @@
* @param other Object to test for equality to this
* @return true if two Complex objects are equal, false if
* object is null, not an instance of Complex, or
- * not equal to this Complex instance.
+ * not equal to this Complex instance
*
*/
public boolean equals(Object other) {
@@ -226,19 +292,50 @@
}
/**
- * Returns true if this complex number is the special Not-a-Number (NaN)
- * value.
+ * Returns true if this complex number is equal to the special
+ * Not-a-Number (NaN) value.
*
- * @return true if the value represented by this object is NaN; false
- * otherwise.
+ * @return true if either or both parts of this complex number take
+ * NaN values; false otherwise.
*/
public boolean isNaN() {
return Double.isNaN(real) || Double.isNaN(imaginary);
}
/**
+ * Returns true if either the real or imaginary part of this complex number
+ * takes an infinite value (either <code>Double.POSITIVE_INFINITY</code> or
+ * <code>Double.NEGATIVE_INFINITY</code>) and neither part
+ * is <code>NaN</code>.
+ *
+ * @return true if one or both parts of this complex number are infinite
+ * and neither part is <code>NaN</code>
+ */
+ public boolean isInfinite() {
+ return !isNaN() &&
+ (Double.isInfinite(real) || Double.isInfinite(imaginary));
+ }
+
+ /**
* Return the product of this complex number and the given complex number.
- *
+ * <p>
+ * Implements the definitional formula:
+ * <pre><code>
+ * (a + bi)(c + di) = (ac - bd) + (ad + bc)i
+ * </code></pre>
+ * <p>
+ * Returns {@link #NaN} if either this or <code>rhs</code> has one or more
+ * NaN parts.
+ * <p>
+ * Returns NaN or infintite values in components of the result per the
+ * definitional formula and and the rules for {@link java.lang.Double}
+ * arithmetic. Examples:
+ * <pre><code>
+ * (1 + i) (INF + i) = INF + INFi
+ * (1 + INFi) (1 - INFi) = INF + NaNi
+ * (-INF + -INFi)(1 + NaNi) = NaN + NaNi
+ * </code></pre>
+ *
* @param rhs the other complex number.
* @return the complex number product.
*/
@@ -246,11 +343,8 @@
if (isNaN() || rhs.isNaN()) {
return NaN;
}
-
- double p = (real + imaginary) * (rhs.getReal() + rhs.getImaginary());
- double ac = real * rhs.getReal();
- double bd = imaginary * rhs.getImaginary();
- return new Complex(ac - bd, p - ac - bd);
+ return new Complex(real * rhs.real - imaginary * rhs.imaginary,
+ real * rhs.imaginary + imaginary * rhs.real);
}
/**
Modified: jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexTest.java?rev=331126&r1=331125&r2=331126&view=diff
==============================================================================
--- jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexTest.java (original)
+++ jakarta/commons/proper/math/branches/MATH_1_1/src/test/org/apache/commons/math/complex/ComplexTest.java Sun Nov 6 10:06:46 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.
@@ -23,6 +23,16 @@
*/
public class ComplexTest extends TestCase {
+ private double inf = Double.POSITIVE_INFINITY;
+ private double neginf = Double.NEGATIVE_INFINITY;
+ private double nan = Double.NaN;
+ private Complex oneInf = new Complex(1, inf);
+ private Complex oneNegInf = new Complex(1, neginf);
+ private Complex infOne = new Complex(inf, 1);
+ private Complex negInfInf = new Complex(neginf, inf);
+ private Complex negInfNegInf = new Complex(neginf, neginf);
+ private Complex oneNaN = new Complex(1, nan);
+
public void testConstructor() {
Complex z = new Complex(3.0, 4.0);
assertEquals(3.0, z.getReal(), 1.0e-5);
@@ -33,7 +43,7 @@
Complex z = new Complex(3.0, Double.NaN);
assertTrue(z.isNaN());
- z = new Complex(Double.NaN, 4.0);
+ z = new Complex(nan, 4.0);
assertTrue(z.isNaN());
z = new Complex(3.0, 4.0);
@@ -47,6 +57,17 @@
public void testAbsNaN() {
assertTrue(Double.isNaN(Complex.NaN.abs()));
+ Complex z = new Complex(inf, nan);
+ assertTrue(Double.isNaN(z.abs()));
+ }
+
+ public void testAbsInfinite() {
+ Complex z = new Complex(inf, 0);
+ assertEquals(inf, z.abs(), 0);
+ z = new Complex(0, neginf);
+ assertEquals(inf, z.abs(), 0);
+ z = new Complex(inf, neginf);
+ assertEquals(inf, z.abs(), 0);
}
public void testAdd() {
@@ -61,6 +82,21 @@
Complex x = new Complex(3.0, 4.0);
Complex z = x.add(Complex.NaN);
assertTrue(z.isNaN());
+ z = new Complex(1, nan);
+ Complex w = x.add(z);
+ assertEquals(w.real, 4.0, 0);
+ assertTrue(Double.isNaN(w.imaginary));
+ }
+
+ public void testAddInfinite() {
+ Complex x = new Complex(1, 1);
+ Complex z = new Complex(inf, 0);
+ Complex w = x.add(z);
+ assertEquals(w.imaginary, 1, 0);
+ assertEquals(inf, w.real, 0);
+
+ x = new Complex(neginf, 0);
+ assertTrue(Double.isNaN(x.add(z).real));
}
public void testConjugate() {
@@ -75,6 +111,13 @@
assertTrue(z.isNaN());
}
+ public void testConjugateInfiinite() {
+ Complex z = new Complex(0, inf);
+ assertEquals(neginf, z.conjugate().imaginary, 0);
+ z = new Complex(0, neginf);
+ assertEquals(inf, z.conjugate().imaginary, 0);
+ }
+
public void testDivide() {
Complex x = new Complex(3.0, 4.0);
Complex y = new Complex(5.0, 6.0);
@@ -83,12 +126,46 @@
assertEquals(2.0 / 61.0, z.getImaginary(), 1.0e-5);
}
+ public void testDivideInfinite() {
+ Complex x = new Complex(3, 4);
+ Complex w = new Complex(neginf, inf);
+ assertTrue(x.divide(w).equals(Complex.ZERO));
+
+ Complex z = w.divide(x);
+ assertTrue(Double.isNaN(z.real));
+ assertEquals(inf, z.imaginary, 0);
+
+ w = new Complex(inf, inf);
+ z = w.divide(x);
+ assertTrue(Double.isNaN(z.imaginary));
+ assertEquals(inf, z.real, 0);
+
+ w = new Complex(1, inf);
+ z = w.divide(w);
+ assertTrue(Double.isNaN(z.real));
+ assertTrue(Double.isNaN(z.imaginary));
+ }
+
public void testDivideNaN() {
Complex x = new Complex(3.0, 4.0);
Complex z = x.divide(Complex.NaN);
assertTrue(z.isNaN());
}
+ public void testDivideNaNInf() {
+ Complex z = oneInf.divide(Complex.ONE);
+ assertTrue(Double.isNaN(z.real));
+ assertEquals(inf, z.imaginary, 0);
+
+ z = negInfNegInf.divide(oneNaN);
+ assertTrue(Double.isNaN(z.real));
+ assertTrue(Double.isNaN(z.imaginary));
+
+ z = negInfInf.divide(Complex.ONE);
+ assertTrue(Double.isNaN(z.real));
+ assertTrue(Double.isNaN(z.imaginary));
+ }
+
public void testMultiply() {
Complex x = new Complex(3.0, 4.0);
Complex y = new Complex(5.0, 6.0);
@@ -101,6 +178,21 @@
Complex x = new Complex(3.0, 4.0);
Complex z = x.multiply(Complex.NaN);
assertTrue(z.isNaN());
+ }
+
+ public void testMultiplyNaNInf() {
+ Complex z = new Complex(1,1);
+ Complex w = z.multiply(infOne);
+ assertEquals(w.real, inf, 0);
+ assertEquals(w.imaginary, inf, 0);
+
+ w = oneInf.multiply(oneNegInf);
+ assertEquals(w.real, inf, 0);
+ assertTrue(Double.isNaN(w.imaginary));
+
+ w = negInfNegInf.multiply(oneNaN);
+ assertTrue(Double.isNaN(w.real));
+ assertTrue(Double.isNaN(w.imaginary));
}
public void testNegate() {
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org