This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git

commit 92c5db5f2b3482c6e1d1dba230d268315b36f3fc
Author: Alex Herbert <aherb...@apache.org>
AuthorDate: Mon Dec 23 00:13:41 2019 +0000

    Update exp() control flow for edge cases.
    
    Added C99 edge cases in the comments.
---
 .../apache/commons/numbers/complex/Complex.java    | 69 +++++++++++++++-------
 1 file changed, 47 insertions(+), 22 deletions(-)

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 0adc915..68dc607 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
@@ -2016,37 +2016,55 @@ public final class Complex implements Serializable  {
      * @see <a 
href="http://functions.wolfram.com/ElementaryFunctions/Exp/";>Exp</a>
      */
     public Complex exp() {
-        // Set the values used to compute exp(real) * cis(im)
-        double expReal;
-        double im = imaginary;
         if (Double.isInfinite(real)) {
+            // Set the scale factor applied to cis(y)
+            double zeroOrInf;
             if (real < 0) {
-                expReal = 0;
-                if (!Double.isFinite(im)) {
-                    // Preserve conjugate equality
-                    im = Math.copySign(1, im);
+                if (!Double.isFinite(imaginary)) {
+                    // (−∞ + i∞) or (−∞ + iNaN) returns (±0 ± i0) (where the 
signs of the
+                    // real and imaginary parts of the result are unspecified).
+                    // Here we preserve the conjugate equality.
+                    return new Complex(0, Math.copySign(0, imaginary));
                 }
+                // (−∞ + iy) returns +0 cis(y), for finite y
+                zeroOrInf = 0;
             } else {
-                if (im == 0 || !Double.isFinite(im)) {
-                    return Double.isInfinite(im) ?
-                        new Complex(real, Double.NaN) :
-                        this;
+                // (+∞ + i0) returns +∞ + i0.
+                if (imaginary == 0) {
+                    return this;
                 }
-                expReal = real;
+                // (+∞ + i∞) or (+∞ + iNaN) returns (±∞ + iNaN) and raises the 
invalid
+                // floating-point exception (where the sign of the real part 
of the
+                // result is unspecified).
+                if (!Double.isFinite(imaginary)) {
+                    return new Complex(real, Double.NaN);
+                }
+                // (+∞ + iy) returns (+∞ cis(y)), for finite nonzero y.
+                zeroOrInf = real;
             }
-        } else if (imaginary == 0) {
-            // Real-only number
-            return Double.isNaN(real) ?
-                this :
-                new Complex(Math.exp(real), imaginary);
+            return new Complex(zeroOrInf * Math.cos(imaginary),
+                               zeroOrInf * Math.sin(imaginary));
         } else if (Double.isNaN(real)) {
+            // (NaN + i0) returns (NaN + i0);
+            // (NaN + iy) returns (NaN + iNaN) and optionally raises the 
invalid floating-point exception
+            // (NaN + iNaN) returns (NaN + iNaN)
+            return imaginary == 0 ? this : NAN;
+        } else if (!Double.isFinite(imaginary)) {
+            // (x + i∞) or (x + iNaN) returns (NaN + iNaN) and raises the 
invalid
+            // floating-point exception, for finite x.
             return NAN;
-        } else {
-            // real is finite
-            expReal = Math.exp(real);
         }
-        return new Complex(expReal * Math.cos(im),
-                           expReal * Math.sin(im));
+        // real and imaginary are finite.
+        // Compute e^a * (cos(b) + i sin(b)).
+
+        // Special case:
+        // (±0 + i0) returns (1 + i0)
+        final double exp = Math.exp(real);
+        if (imaginary == 0) {
+            return new Complex(exp, imaginary);
+        }
+        return new Complex(exp * Math.cos(imaginary),
+                           exp * Math.sin(imaginary));
     }
 
     /**
@@ -2105,6 +2123,12 @@ public final class Complex implements Serializable  {
      * @see #arg()
      */
     private Complex log(UnaryOperation log, double logOf2, ComplexConstructor 
constructor) {
+        // TODO - Add edge cases with values for abs() close to 1
+        // These should be handled correctly.
+
+        // Change this to use a method based on glibc with detection of values 
of
+        // abs() close to 1 and switch to using log1p(abs - 1).
+
         // All ISO C99 edge cases satisfied by the Math library.
         // Make computation overflow safe.
 
@@ -2116,6 +2140,7 @@ public final class Complex implements Serializable  {
 
         // Use the safe region defined for atanh to avoid over/underflow for 
x^2
         if (inRegion(x, y, SAFE_LOWER, SAFE_UPPER)) {
+            //return constructor.create(log.apply(abs()), arg());
             return constructor.create(0.5 * log.apply(x * x + y * y), arg());
         }
 

Reply via email to