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 <[email protected]> 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) {
