Repository: commons-numbers
Updated Branches:
  refs/heads/master 2f23f3e17 -> 84821835d


NUMBERS-71: Complex multiplication and division methods have implemented
C++11 standards.

Project: http://git-wip-us.apache.org/repos/asf/commons-numbers/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-numbers/commit/84821835
Tree: http://git-wip-us.apache.org/repos/asf/commons-numbers/tree/84821835
Diff: http://git-wip-us.apache.org/repos/asf/commons-numbers/diff/84821835

Branch: refs/heads/master
Commit: 84821835de201e2fc90c5a362a9bd8fdfcb15079
Parents: 2f23f3e
Author: Eric Barnhill <ericbarnh...@apache.org>
Authored: Tue Mar 13 10:48:58 2018 +0100
Committer: Eric Barnhill <ericbarnh...@apache.org>
Committed: Tue Mar 13 10:48:58 2018 +0100

----------------------------------------------------------------------
 .../apache/commons/numbers/complex/Complex.java | 141 +++++++++++--------
 .../commons/numbers/complex/ComplexTest.java    |   7 +-
 2 files changed, 86 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/84821835/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
----------------------------------------------------------------------
diff --git 
a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
 
b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
index c36bea1..f1991e8 100644
--- 
a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
+++ 
b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
@@ -265,60 +265,53 @@ public class Complex implements Serializable  {
      *    c + di         c<sup>2</sup> + d<sup>2</sup>
      *  </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>
-     * {@code Infinite} and {@code NaN} values are handled according to the
-     * following rules, applied in the order presented:
-     * <ul>
-     *  <li>If {@code divisor} equals {@link #ZERO}, {@link #NAN} is returned.
-     *  </li>
-     *  <li>If {@code this} and {@code divisor} are both infinite,
-     *   {@link #NAN} is returned.
-     *  </li>
-     *  <li>If {@code this} is finite (i.e., has no {@code Infinite} or
-     *   {@code NaN} parts) and {@code divisor} is infinite (one or both parts
-     *   infinite), {@link #ZERO} is returned.
-     *  </li>
-     *  <li>If {@code this} is infinite and {@code divisor} is finite,
-     *   {@code NaN} values are returned in the parts of the result if the
-     *   {@link java.lang.Double} rules applied to the definitional formula
-     *   force {@code NaN} results.
-     *  </li>
-     * </ul>
+     *
+     *
+     * Recalculates to recover infinities as specified in C.99
+     * standard G.5.1. Method is fully in accordance with
+     * C++11 standards for complex numbers.
      *
      * @param divisor Value by which this {@code Complex} is to be divided.
      * @return {@code this / divisor}.
      */
     public Complex divide(Complex divisor) {
 
-        final double c = divisor.real;
-        final double d = divisor.imaginary;
-        if (c == 0 &&
-            d == 0) {
-            return NAN;
+        double a = real;
+        double b = imaginary;
+        double c = divisor.getReal();
+        double d = divisor.getImaginary();
+        int ilogbw = 0;
+        double logbw = Math.log(Math.max(Math.abs(c), Math.abs(d))) / 
Math.log(2);
+        if (!Double.isInfinite(logbw)) {
+               ilogbw = (int)logbw;
+               c = Math.scalb(c, -ilogbw);
+               d = Math.scalb(d, -ilogbw);
         }
-
-        if ((Double.isInfinite(c) ||
-             Double.isInfinite(d)) &&
-            (Double.isInfinite(real) ||
-             Double.isInfinite(imaginary))) {
-            return ZERO;
+        double denom = c*c + d*d;
+        double x = Math.scalb( (a*c + b*d) / denom, -ilogbw);
+        double y = Math.scalb( (b*c - a*d) / denom, -ilogbw);
+        if (Double.isNaN(x) && Double.isNaN(y)) {
+               if ((denom == 0.0) &&
+                               (!Double.isNaN(a) || !Double.isNaN(b))) {
+                       x = Math.copySign(Double.POSITIVE_INFINITY, c) * a;
+                       y = Math.copySign(Double.POSITIVE_INFINITY, c) * b;
+               } else if ((Double.isInfinite(a) && Double.isInfinite(b)) &&
+                               !Double.isInfinite(c) & !Double.isInfinite(d)) {
+                       a = Math.copySign(Double.isInfinite(a) ? 1.0 : 0.0, a);
+                       b = Math.copySign(Double.isInfinite(b) ? 1.0 : 0.0, b);
+                       x = Double.POSITIVE_INFINITY * (a*c + b*d);
+                       y = Double.POSITIVE_INFINITY * (b*c - a*d);
+               } else if (Double.isInfinite(logbw) &&
+                               !Double.isInfinite(a) & !Double.isInfinite(b)) {
+                       c = Math.copySign(Double.isInfinite(c) ? 1.0 : 0.0, c);
+                       d = Math.copySign(Double.isInfinite(d) ? 1.0 : 0.0, d);
+                       x = 0.0 * (a*c + b*d);
+                       y = 0.0 * (b*c - a*d);
+               }
         }
+        return new Complex(x, y);
+
 
-        if (Math.abs(c) < Math.abs(d)) {
-            final double q = c / d;
-            final double denominator = c * q + d;
-            return new Complex((real * q + imaginary) / denominator,
-                               (imaginary * q - real) / denominator);
-        } else {
-            final double q = d / c;
-            final double denominator = d * q + c;
-            return new Complex((imaginary * q + real) / denominator,
-                               (imaginary - real * q) / denominator);
-        }
     }
 
     /**
@@ -330,15 +323,7 @@ public class Complex implements Serializable  {
      * @see #divide(Complex)
      */
     public Complex divide(double divisor) {
-        if (divisor == 0d) {
-            return NAN;
-        }
-        if (Double.isInfinite(divisor)) {
-            return !(Double.isInfinite(real) ||
-                     Double.isInfinite(imaginary)) ? ZERO : NAN;
-        }
-        return new Complex(real / divisor,
-                           imaginary  / divisor);
+        return divide(new Complex(divisor, 0));
     }
 
     /**
@@ -550,15 +535,54 @@ public class Complex implements Serializable  {
      *
      *   {@code (a + bi)(c + di) = (ac - bd) + (ad + bc)i}
      *
-     * Returns finite values in components of the result per the definitional
-     * formula in all remaining cases.
+     * Recalculates to recover infinities as specified in C.99
+     * standard G.5.1. Method is fully in accordance with
+     * C++11 standards for complex numbers.
      *
      * @param  factor value to be multiplied by this {@code Complex}.
      * @return {@code this * factor}.
      */
     public Complex multiply(Complex factor) {
-        return new Complex(real * factor.real - imaginary * factor.imaginary,
-                           real * factor.imaginary + imaginary * factor.real);
+        double a = real;
+        double b = imaginary;
+        double c = factor.getReal();
+        double d = factor.getImaginary();
+        final double ac = a*c;
+        final double bd = b*d;
+        final double ad = a*d;
+        final double bc = b*c;
+        double x = ac - bd;
+        double y = ad + bc;
+        if (Double.isNaN(a) && Double.isNaN(b)) {
+               boolean recalc = false;
+               if (Double.isInfinite(a) || Double.isInfinite(b)) {
+                       a = Math.copySign(Double.isInfinite(a) ? 1.0 : 0.0, a);
+                       b = Math.copySign(Double.isInfinite(a) ? 1.0 : 0.0, a);
+                       if (Double.isNaN(c)) c = Math.copySign(0.0,  c);
+                       if (Double.isNaN(d)) d = Math.copySign(0.0,  d);
+                       recalc = true;
+               }
+               if (Double.isInfinite(c) || Double.isInfinite(d)) {
+                       c = Math.copySign(Double.isInfinite(c) ? 1.0 : 0.0, c);
+                       d = Math.copySign(Double.isInfinite(d) ? 1.0 : 0.0, d);
+                       if (Double.isNaN(a)) a = Math.copySign(0.0,  a);
+                       if (Double.isNaN(b)) b = Math.copySign(0.0,  b);
+                       recalc = true;
+               }
+               if (!recalc && (Double.isInfinite(ac) || Double.isInfinite(bd) 
||
+                               Double.isInfinite(ad) || 
Double.isInfinite(bc))) {
+                       if (Double.isNaN(a)) a = Math.copySign(0.0,  a);
+                       if (Double.isNaN(b)) b = Math.copySign(0.0,  b);
+                       if (Double.isNaN(c)) c = Math.copySign(0.0,  c);
+                       if (Double.isNaN(d)) d = Math.copySign(0.0,  d);
+                       recalc = true;
+               }
+               if (recalc) {
+                       x = Double.POSITIVE_INFINITY * (a*c - b*d);
+                       y = Double.POSITIVE_INFINITY * (a*d + b*c);
+               }
+        }
+        return new Complex(x, y);
     }
 
     /**
@@ -1301,4 +1325,5 @@ public class Complex implements Serializable  {
             !Double.isInfinite(d) &&
             d != 0;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/84821835/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
----------------------------------------------------------------------
diff --git 
a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
 
b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
index b780f4b..d6170a6 100644
--- 
a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
+++ 
b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
@@ -186,8 +186,7 @@ public class ComplexTest {
     public void testDivideZero() {
         Complex x = Complex.ofCartesian(3.0, 4.0);
         Complex z = x.divide(Complex.ZERO);
-        // Assert.assertEquals(z, Complex.INF); // See MATH-657
-        Assert.assertEquals(z, NAN);
+        Assert.assertEquals(z, Complex.INF);
     }
 
     @Test
@@ -215,8 +214,8 @@ public class ComplexTest {
        Assert.assertTrue(Double.isNaN(z.getImaginary()));
 
        z = negInfInf.divide(Complex.ONE);
-       Assert.assertTrue(Double.isNaN(z.getReal()));
-       Assert.assertTrue(Double.isNaN(z.getImaginary()));
+       Assert.assertTrue(Double.isInfinite(z.getReal()));
+       Assert.assertTrue(Double.isInfinite(z.getImaginary()));
     }
 
     @Test

Reply via email to