You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2020/01/02 15:04:44 UTC

[commons-numbers] 02/04: Update C99 standard for acosh and tanh

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 f1b8cc31888aa284e39249708787b37164c5d436
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Wed Jan 1 22:49:41 2020 +0000

    Update C99 standard for acosh and tanh
    
    See:
    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1892.htm#dr_471
---
 .../apache/commons/numbers/complex/Complex.java    | 31 ++++++++++++++++------
 .../commons/numbers/complex/CStandardTest.java     | 17 +++++++++---
 2 files changed, 37 insertions(+), 11 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 5b710a2..79b2408 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
@@ -1785,7 +1785,8 @@ public final class Complex implements Serializable  {
      * <li>{@code z.conj().acosh() == z.acosh().conj()}.
      * <li>If {@code z} is ±0 + i0, returns +0 + iπ/2.
      * <li>If {@code z} is x + i∞ for finite x, returns +∞ + iπ/2.
-     * <li>If {@code z} is x + iNaN for finite x, returns NaN + iNaN.
+     * <li>If {@code z} is 0 + iNaN, returns NaN + iπ/2 <sup>[1]</sup>.
+     * <li>If {@code z} is x + iNaN for finite non-zero x, returns NaN + iNaN.
      * <li>If {@code z} is −∞ + iy for positive-signed finite y, returns +∞ + iπ.
      * <li>If {@code z} is +∞ + iy for positive-signed finite y, returns +∞ + i0.
      * <li>If {@code z} is −∞ + i∞, returns +∞ + i3π/4.
@@ -1796,6 +1797,10 @@ public final class Complex implements Serializable  {
      * <li>If {@code z} is NaN + iNaN, returns NaN + iNaN.
      * </ul>
      *
+     * <p>[1] This has been updated as per
+     * <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1892.htm#dr_471">
+     * DR 471: Complex math functions cacosh and ctanh</a>.
+     *
      * <p>This function is computed using the trigonomic identity:
      *
      * <p>\[ \cosh^{-1}(z) = \pm i \cos^{-1}(z) \]
@@ -1809,11 +1814,13 @@ public final class Complex implements Serializable  {
     public Complex acosh() {
         // Define in terms of acos
         // acosh(z) = +-i acos(z)
-        // Handle special case:
+        // Note the special case:
         // acos(+-0 + iNaN) = π/2 + iNaN
-        // acosh(x + iNaN) = NaN + iNaN for all finite x (including zero)
-        if (Double.isNaN(imaginary) && Double.isFinite(real)) {
-            return NAN;
+        // acosh(0 + iNaN) = NaN + iπ/2
+        // will not appropriately multiply by I to maintain positive imaginary if
+        // acos() imaginary computes as NaN. So do this explicitly.
+        if (Double.isNaN(imaginary) && real == 0) {
+            return new Complex(Double.NaN, PI_OVER_2);
         }
         return acos(real, imaginary, (re, im) ->
             // Set the sign appropriately for real >= 0
@@ -2517,6 +2524,8 @@ public final class Complex implements Serializable  {
         return tanh(-imaginary, real, Complex::multiplyNegativeI);
     }
 
+    // TODO
+
     /**
      * Returns the
      * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html">
@@ -2535,8 +2544,10 @@ public final class Complex implements Serializable  {
      * <li>{@code z.conj().tanh() == z.tanh().conj()}.
      * <li>This is an odd function: \( \tanh(z) = -\tanh(-z) \).
      * <li>If {@code z} is +0 + i0, returns +0 + i0.
-     * <li>If {@code z} is x + i∞ for finite x, returns NaN + iNaN.
-     * <li>If {@code z} is x + iNaN for finite x, returns NaN + iNaN.
+     * <li>If {@code z} is 0 + i∞, returns 0 + iNaN.
+     * <li>If {@code z} is x + i∞ for finite non-zero x, returns NaN + iNaN.
+     * <li>If {@code z} is 0 + iNaN, returns 0 + iNAN.
+     * <li>If {@code z} is x + iNaN for finite non-zero x, returns NaN + iNaN.
      * <li>If {@code z} is +∞ + iy for positive-signed finite y, returns 1 + i0 sin(2y).
      * <li>If {@code z} is +∞ + i∞, returns 1 ± i0 (where the sign of the imaginary part of the result is unspecified).
      * <li>If {@code z} is +∞ + iNaN, returns 1 ± i0 (where the sign of the imaginary part of the result is unspecified).
@@ -2545,6 +2556,10 @@ public final class Complex implements Serializable  {
      * <li>If {@code z} is NaN + iNaN, returns NaN + iNaN.
      * </ul>
      *
+     * <p>[1] This has been updated as per
+     * <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1892.htm#dr_471">
+     * DR 471: Complex math functions cacosh and ctanh</a>.
+     *
      * <p>This is implemented using real \( x \) and imaginary \( y \) parts:
      *
      * <p>\[ \tan(x + iy) = \frac{\sinh(2x)}{\cosh(2x)+\cos(2y)} + i \frac{\sin(2y)}{\cosh(2x)+\cos(2y)} \]
@@ -2581,7 +2596,7 @@ public final class Complex implements Serializable  {
                 // Identity: sin x / (1 + cos x) = tan(x/2)
                 return constructor.create(real, Math.tan(imaginary));
             }
-            return constructor.create(Double.NaN, Double.NaN);
+            return constructor.create(real, Double.NaN);
         }
         if (imaginary == 0) {
             if (Double.isNaN(real)) {
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
index b47ec5e..374d565 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
@@ -65,6 +65,7 @@ public class CStandardTest {
     private static final Complex nanInf = complex(nan, inf);
     private static final Complex nanNegInf = complex(nan, negInf);
     private static final Complex nanZero = complex(nan, 0);
+    private static final Complex nanPiTwo = complex(nan, piOverTwo);
     private static final Complex piTwoNaN = complex(piOverTwo, nan);
     private static final Complex piNegInf = complex(Math.PI, negInf);
     private static final Complex piTwoNegInf = complex(piOverTwo, negInf);
@@ -819,6 +820,9 @@ public class CStandardTest {
 
     /**
      * ISO C Standard G.6.2.1.
+     *
+     * @see <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1892.htm#dr_471">
+     *   Complex math functions cacosh and ctanh</a>
      */
     @Test
     public void testAcosh() {
@@ -829,7 +833,9 @@ public class CStandardTest {
         for (double x : finite) {
             assertComplex(complex(x, inf), operation, infPiTwo);
         }
-        for (double x : finite) {
+        assertComplex(zeroNaN, operation, nanPiTwo);
+        assertComplex(negZeroNaN, operation, nanPiTwo);
+        for (double x : nonZeroFinite) {
             assertComplex(complex(x, nan), operation, NAN);
         }
         for (double y : positiveFinite) {
@@ -974,6 +980,9 @@ public class CStandardTest {
 
     /**
      * ISO C Standard G.6.2.6.
+     *
+     * @see <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1892.htm#dr_471">
+     *   Complex math functions cacosh and ctanh</a>
      */
     @Test
     public void testTanh() {
@@ -982,10 +991,12 @@ public class CStandardTest {
         assertConjugateEquality(operation);
         assertFunctionType(operation, type);
         assertComplex(Complex.ZERO, operation, Complex.ZERO, type);
-        for (double x : finite) {
+        assertComplex(zeroInf, operation, zeroNaN, type);
+        for (double x : nonZeroFinite) {
             assertComplex(complex(x, inf), operation, NAN, type);
         }
-        for (double x : finite) {
+        assertComplex(zeroNaN, operation, zeroNaN, type);
+        for (double x : nonZeroFinite) {
             assertComplex(complex(x, nan), operation, NAN, type);
         }
         for (double y : positiveFinite) {