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 5d9156bfe79858e804d91b3a2da3e9353b2f2506
Author: aherbert <aherb...@apache.org>
AuthorDate: Thu Dec 19 17:31:59 2019 +0000

    Added atanh assumptions test to check the safe upper and lower limits.
    
    Updated the atanh code to use the boost assumptions.
---
 .../apache/commons/numbers/complex/Complex.java    |  25 +-
 .../commons/numbers/complex/ComplexTest.java       | 343 ++++++++++++---------
 2 files changed, 198 insertions(+), 170 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 11f468f..684faa7 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
@@ -1719,13 +1719,12 @@ public final class Complex implements Serializable  {
             return NAN;
         } else {
             // x && y are finite or infinite.
-            // Cases for very large finite are handled as if infinite.
 
             // Check the safe region.
             // The lower and upper bounds have been copied from 
boost::math::atanh.
             // They are different from the safe region for asin and acos.
-            // x >= SAFE_UPPER: (1-x) == x && x^2 -> inf
-            // x <= SAFE_LOWER: x^2 -> 0
+            // x >= SAFE_UPPER: (1-x) == x
+            // x <= SAFE_LOWER: 1 - x^2 = 1
 
             if ((x > SAFE_LOWER) && (x < SAFE_UPPER) && (y > SAFE_LOWER) && (y 
< SAFE_UPPER)) {
                 // Normal computation within a safe region.
@@ -1762,35 +1761,29 @@ public final class Complex implements Serializable  {
                 // real = Math.log1p(4x / (1 + x(x-2) + y^2))
                 // without either overflow or underflow in the squared terms.
                 if (x >= SAFE_UPPER) {
-                    // (1-x) = x to machine precision
+                    // (1-x) = -x to machine precision:
+                    // log1p(4x / (x^2 + y^2))
                     if (isPosInfinite(x) || isPosInfinite(y)) {
                         re = 0;
                     } else if (y >= SAFE_UPPER) {
                         // Big x and y: divide by x*y
-                        // This has been modified from the boost version to
-                        // include 1/(x*y) and -2/y. These are harmless if
-                        // machine precision prevents their addition to have 
an effect:
-                        // 1/(x*y) -> 0
-                        // (x-2) -> x
-                        re = Math.log1p((4 / y) / (1 / (x * y) + (x - 2) / y + 
y / x));
+                        re = Math.log1p((4 / y) / (x / y + y / x));
                     } else if (y > 1) {
                         // Big x: divide through by x:
-                        // This has been modified from the boost version to
-                        // include 1/x and -2:
-                        re = Math.log1p(4 / (1 / x + x - 2 + y * y / x));
+                        re = Math.log1p(4 / (x + y * y / x));
                     } else {
                         // Big x small y, as above but neglect y^2/x:
-                        re = Math.log1p(4 / (1 / x + x - 2));
+                        re = Math.log1p(4 / x);
                     }
                 } else if (y >= SAFE_UPPER) {
                     if (x > 1) {
                         // Big y, medium x, divide through by y:
                         final double mxp1 = 1 - x;
-                        re = Math.log1p((4 * x / y) / (y + mxp1 * mxp1 / y));
+                        re = Math.log1p((4 * x / y) / (mxp1 * mxp1 / y + y));
                     } else {
                         // Big y, small x, as above but neglect (1-x)^2/y:
                         // Note: The boost version has no log1p here.
-                        // This will tend towards 0 and log1p(0) = 0.
+                        // This will tend towards 0 and log1p(0) = 0 so it may 
not matter.
                         re = Math.log1p(4 * x / y / y);
                     }
                 } else if (x != 1) {
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 ec395e2..d5f54cd 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
@@ -58,9 +58,7 @@ public class ComplexTest {
      * Used to test the number category of a Complex.
      */
     private enum NumberType {
-        NAN,
-        INFINITE,
-        FINITE
+        NAN, INFINITE, FINITE
     }
 
     /**
@@ -121,7 +119,8 @@ public class ComplexTest {
         assertNumberType(-inf, 0, NumberType.INFINITE);
         assertNumberType(0, inf, NumberType.INFINITE);
         assertNumberType(0, -inf, NumberType.INFINITE);
-        // A complex or imaginary value with at least one infinite part is 
regarded as an infinity
+        // A complex or imaginary value with at least one infinite part is 
regarded as an
+        // infinity
         // (even if its other part is a NaN).
         assertNumberType(inf, nan, NumberType.INFINITE);
         assertNumberType(-inf, nan, NumberType.INFINITE);
@@ -151,8 +150,8 @@ public class ComplexTest {
         count += isInfinite ? 1 : 0;
         count += isFinite ? 1 : 0;
         Assertions.assertEquals(1, count,
-            () -> String.format("Complex can be only one type: isNaN=%s, 
isInfinite=%s, isFinite=%s: %s",
-                                isNaN, isInfinite, isFinite, z));
+            () -> String.format("Complex can be only one type: isNaN=%s, 
isInfinite=%s, isFinite=%s: %s", isNaN,
+                isInfinite, isFinite, z));
         switch (type) {
         case FINITE:
             Assertions.assertTrue(isFinite, () -> "not finite: " + z);
@@ -168,7 +167,6 @@ public class ComplexTest {
         }
     }
 
-
     @Test
     public void testProj() {
         final Complex z = Complex.ofCartesian(3.0, 4.0);
@@ -759,8 +757,8 @@ public class ComplexTest {
                 final Complex z = c.multiply(Complex.I);
                 // Does not work when imaginary part is +0.0.
                 if (Double.compare(b, 0.0) == 0) {
-                    // (-0.0, 0.0).multiply( (0,1) ) => (-0.0, 0.0)   expected 
(-0.0,-0.0)
-                    // ( 0.0, 0.0).multiply( (0,1) ) => ( 0.0, 0.0)   expected 
(-0.0, 0.0)
+                    // (-0.0, 0.0).multiply( (0,1) ) => (-0.0, 0.0) expected 
(-0.0,-0.0)
+                    // ( 0.0, 0.0).multiply( (0,1) ) => ( 0.0, 0.0) expected 
(-0.0, 0.0)
                     Assertions.assertEquals(0, z.getReal(), 0.0);
                     Assertions.assertEquals(0, z.getImaginary(), 0.0);
                     Assertions.assertNotEquals(x, z);
@@ -788,16 +786,20 @@ public class ComplexTest {
                 final Complex z2 = c.multiply(Complex.I).negate();
                 // Does not work when imaginary part is -0.0.
                 if (Double.compare(b, -0.0) == 0) {
-                    // (-0.0,-0.0).multiply( (-0.0,-1) ) => ( 0.0, 0.0)   
expected (-0.0, 0.0)
-                    // ( 0.0,-0.0).multiply( (-0.0,-1) ) => (-0.0, 0.0)   
expected (-0.0,-0.0)
+                    // (-0.0,-0.0).multiply( (-0.0,-1) ) => ( 0.0, 0.0) 
expected (-0.0,
+                    // 0.0)
+                    // ( 0.0,-0.0).multiply( (-0.0,-1) ) => (-0.0, 0.0) 
expected
+                    // (-0.0,-0.0)
                     Assertions.assertEquals(0, z.getReal(), 0.0);
                     Assertions.assertEquals(0, z.getImaginary(), 0.0);
                     Assertions.assertNotEquals(x, z);
-                    // When multiply by I.negate() fails multiply by I then 
negate() works!
+                    // When multiply by I.negate() fails multiply by I then 
negate()
+                    // works!
                     Assertions.assertEquals(x, z2);
                 } else {
                     Assertions.assertEquals(x, z);
-                    // When multiply by I.negate() works multiply by I then 
negate() fails!
+                    // When multiply by I.negate() works multiply by I then 
negate()
+                    // fails!
                     Assertions.assertNotEquals(x, z2);
                 }
             }
@@ -805,23 +807,23 @@ public class ComplexTest {
     }
 
     /**
-     * Arithmetic test using combinations of +/- x for real, imaginary and
-     * and the double argument for add, subtract, subtractFrom, multiply and 
divide,
-     * where x is zero or non-zero.
+     * Arithmetic test using combinations of +/- x for real, imaginary and and 
the double
+     * argument for add, subtract, subtractFrom, multiply and divide, where x 
is zero or
+     * non-zero.
      *
-     * <p>The differences to the same argument as a Complex are tested. The 
only differences
-     * should be the sign of zero in certain cases.
+     * <p>The differences to the same argument as a Complex are tested. The 
only
+     * differences should be the sign of zero in certain cases.
      */
     @Test
     public void testSignedArithmetic() {
         // The following lists the conditions for the double primitive 
operation where
         // the Complex operation is different. Here the double argument can be:
-        // x   : any value
-        // +x  : positive
+        // x : any value
+        // +x : positive
         // +0.0: positive zero
-        // -x  : negative
+        // -x : negative
         // -0.0: negative zero
-        // 0   : any zero
+        // 0 : any zero
         // use y for any non-zero value
 
         // Check the known fail cases using an integer as a bit set.
@@ -839,17 +841,22 @@ public class ComplexTest {
         // and the javadoc in Complex does not break down the actual cases.
 
         // 16: (x,-0.0) + x
-        assertSignedZeroArithmetic("addReal", Complex::add, 
ComplexTest::ofReal, Complex::add, 
0b1111000000000000111100000000000011110000000000001111L);
+        assertSignedZeroArithmetic("addReal", Complex::add, 
ComplexTest::ofReal, Complex::add,
+            0b1111000000000000111100000000000011110000000000001111L);
         // 16: (-0.0,x) + x
-        assertSignedZeroArithmetic("addImaginary", Complex::addImaginary, 
ComplexTest::ofImaginary, Complex::add, 0b1111111111111111L);
+        assertSignedZeroArithmetic("addImaginary", Complex::addImaginary, 
ComplexTest::ofImaginary, Complex::add,
+            0b1111111111111111L);
         // 0:
         assertSignedZeroArithmetic("subtractReal", Complex::subtract, 
ComplexTest::ofReal, Complex::subtract, 0);
         // 0:
-        assertSignedZeroArithmetic("subtractImaginary", 
Complex::subtractImaginary, ComplexTest::ofImaginary, Complex::subtract, 0);
+        assertSignedZeroArithmetic("subtractImaginary", 
Complex::subtractImaginary, ComplexTest::ofImaginary,
+            Complex::subtract, 0);
         // 16: x - (x,+0.0)
-        assertSignedZeroArithmetic("subtractFromReal", Complex::subtractFrom, 
ComplexTest::ofReal, (y, z) -> z.subtract(y), 
0b11110000000000001111000000000000111100000000000011110000L);
+        assertSignedZeroArithmetic("subtractFromReal", Complex::subtractFrom, 
ComplexTest::ofReal,
+            (y, z) -> z.subtract(y), 
0b11110000000000001111000000000000111100000000000011110000L);
         // 16: x - (+0.0,x)
-        assertSignedZeroArithmetic("subtractFromImaginary", 
Complex::subtractFromImaginary, ComplexTest::ofImaginary, (y, z) -> 
z.subtract(y), 0b11111111111111110000000000000000L);
+        assertSignedZeroArithmetic("subtractFromImaginary", 
Complex::subtractFromImaginary, ComplexTest::ofImaginary,
+            (y, z) -> z.subtract(y), 0b11111111111111110000000000000000L);
         // 4: (-0.0,-x) * +x
         // 4: (+0.0,-0.0) * x
         // 4: (+0.0,x) * -x
@@ -859,7 +866,8 @@ public class ComplexTest {
         // 2: (+y,-x) * -0.0
         // 2: (+x,-y) * +0.0
         // 2: (+x,+y) * -0.0
-        assertSignedZeroArithmetic("multiplyReal", Complex::multiply, 
ComplexTest::ofReal, Complex::multiply, 
0b1001101011011000000100000001000010111010111110000101000001010L);
+        assertSignedZeroArithmetic("multiplyReal", Complex::multiply, 
ComplexTest::ofReal, Complex::multiply,
+            0b1001101011011000000100000001000010111010111110000101000001010L);
         // 4: (-0.0,+x) * +x
         // 2: (+0.0,-0.0) * -x
         // 4: (+0.0,+0.0) * x
@@ -867,23 +875,25 @@ public class ComplexTest {
         // 2: (-y,+x) * +0.0
         // 4: (+y,x) * -0.0
         // 2: (+0.0,+/-y) * -/+0
-        // 2: (+y,+/-0.0) * +/-y  (sign 0.0 matches sign y)
+        // 2: (+y,+/-0.0) * +/-y (sign 0.0 matches sign y)
         // 2: (+y,+x) * +0.0
-        assertSignedZeroArithmetic("multiplyImaginary", 
Complex::multiplyImaginary, ComplexTest::ofImaginary, Complex::multiply, 
0b11000110110101001000000010000001110001111101011010000010100000L);
+        assertSignedZeroArithmetic("multiplyImaginary", 
Complex::multiplyImaginary, ComplexTest::ofImaginary,
+            Complex::multiply, 
0b11000110110101001000000010000001110001111101011010000010100000L);
         // 2: (-0.0,0) / +y
         // 2: (+0.0,+x) / -y
         // 2: (-x,0) / -y
         // 1: (-0.0,+y) / +y
         // 1: (-y,+0.0) / -y
-        assertSignedZeroArithmetic("divideReal", Complex::divide, 
ComplexTest::ofReal, Complex::divide, 
0b100100001000000010000001000000011001000L);
+        assertSignedZeroArithmetic("divideReal", Complex::divide, 
ComplexTest::ofReal, Complex::divide,
+            0b100100001000000010000001000000011001000L);
 
-        // DivideImaginary has its own test as the result is not always equal 
ignoring the sign.
+        // DivideImaginary has its own test as the result is not always equal 
ignoring the
+        // sign.
     }
 
-    private static void assertSignedZeroArithmetic(String name,
-            BiFunction<Complex, Double, Complex> doubleOperation,
-            DoubleFunction<Complex> doubleToComplex,
-            BiFunction<Complex, Complex, Complex> complexOperation, long 
expectedFailures) {
+    private static void assertSignedZeroArithmetic(String name, 
BiFunction<Complex, Double, Complex> doubleOperation,
+        DoubleFunction<Complex> doubleToComplex, BiFunction<Complex, Complex, 
Complex> complexOperation,
+        long expectedFailures) {
         // With an operation on zero or non-zero arguments
         final double[] arguments = {-0.0, 0.0, -2, 3};
         for (final double a : arguments) {
@@ -896,21 +906,22 @@ public class ComplexTest {
                     expectedFailures >>>= 1;
                     // Check the same answer. Sign is allowed to be different 
for zero.
                     Assertions.assertEquals(y.getReal(), z.getReal(), 0, () -> 
c + " " + name + " " + arg + ": real");
-                    Assertions.assertEquals(y.getImaginary(), 
z.getImaginary(), 0, () -> c + " " + name + " " + arg + ": imaginary");
-                    Assertions.assertEquals(expectedFailure, !y.equals(z), () 
-> c + " " + name + " " + arg + ": sign-difference");
+                    Assertions.assertEquals(y.getImaginary(), 
z.getImaginary(), 0,
+                        () -> c + " " + name + " " + arg + ": imaginary");
+                    Assertions.assertEquals(expectedFailure, !y.equals(z),
+                        () -> c + " " + name + " " + arg + ": 
sign-difference");
                 }
             }
         }
     }
 
     /**
-     * Arithmetic test using combinations of +/- x for real, imaginary and
-     * and the double argument for divideImaginary,
-     * where x is zero or non-zero.
+     * Arithmetic test using combinations of +/- x for real, imaginary and and 
the double
+     * argument for divideImaginary, where x is zero or non-zero.
      *
-     * <p>The differences to the same argument as a Complex are tested. This 
checks for sign
-     * differences of zero or, if divide by zero, that the result is equal
-     * to divide by zero using a Complex then multiplied by I.
+     * <p>The differences to the same argument as a Complex are tested. This 
checks for
+     * sign differences of zero or, if divide by zero, that the result is 
equal to divide
+     * by zero using a Complex then multiplied by I.
      */
     @Test
     public void testDivideImaginaryArithmetic() {
@@ -923,7 +934,8 @@ public class ComplexTest {
         // 2: (+0.0,+/-y) / +0.0
         // 4: (-y,x) / +0.0
         // 4: (y,x) / +0.0
-        // If multiplied by -I all the divide by -0.0 cases have sign errors 
and / +0.0 is OK.
+        // If multiplied by -I all the divide by -0.0 cases have sign errors 
and / +0.0 is
+        // OK.
         long expectedFailures = 
0b11001101111011001100110011001110110011110010000111001101000000L;
         // With an operation on zero or non-zero arguments
         final double[] arguments = {-0.0, 0.0, -2, 3};
@@ -935,7 +947,8 @@ public class ComplexTest {
                     Complex z = c.divide(ofImaginary(arg));
                     final boolean expectedFailure = (expectedFailures & 0x1) 
== 1;
                     expectedFailures >>>= 1;
-                    // If divide by zero then the divide(Complex) method 
matches divide by real.
+                    // If divide by zero then the divide(Complex) method 
matches divide by
+                    // real.
                     // To match divide by imaginary requires multiplication by 
I.
                     if (arg == 0) {
                         // Same result if multiplied by I. The sign may not 
match so
@@ -948,10 +961,14 @@ public class ComplexTest {
                         Assertions.assertEquals(ya, za, () -> c + " 
divideImaginary " + arg + ": real");
                         Assertions.assertEquals(yb, zb, () -> c + " 
divideImaginary " + arg + ": imaginary");
                     } else {
-                        // Check the same answer. Sign is allowed to be 
different for zero.
-                        Assertions.assertEquals(y.getReal(), z.getReal(), 0, 
() -> c + " divideImaginary " + arg + ": real");
-                        Assertions.assertEquals(y.getImaginary(), 
z.getImaginary(), 0, () -> c + " divideImaginary " + arg + ": imaginary");
-                        Assertions.assertEquals(expectedFailure, !y.equals(z), 
() -> c + " divideImaginary " + arg + ": sign-difference");
+                        // Check the same answer. Sign is allowed to be 
different for
+                        // zero.
+                        Assertions.assertEquals(y.getReal(), z.getReal(), 0,
+                            () -> c + " divideImaginary " + arg + ": real");
+                        Assertions.assertEquals(y.getImaginary(), 
z.getImaginary(), 0,
+                            () -> c + " divideImaginary " + arg + ": 
imaginary");
+                        Assertions.assertEquals(expectedFailure, !y.equals(z),
+                            () -> c + " divideImaginary " + arg + ": 
sign-difference");
                     }
                 }
             }
@@ -1175,15 +1192,13 @@ public class ComplexTest {
     @Test
     public void testFloatingPointEqualsPrecondition1() {
         Assertions.assertThrows(NullPointerException.class,
-            () -> Complex.equals(Complex.ofCartesian(3.0, 4.0), null, 3)
-        );
+            () -> Complex.equals(Complex.ofCartesian(3.0, 4.0), null, 3));
     }
 
     @Test
     public void testFloatingPointEqualsPrecondition2() {
         Assertions.assertThrows(NullPointerException.class,
-            () -> Complex.equals(null, Complex.ofCartesian(3.0, 4.0), 3)
-        );
+            () -> Complex.equals(null, Complex.ofCartesian(3.0, 4.0), 3));
     }
 
     @Test
@@ -1304,28 +1319,23 @@ public class ComplexTest {
 
     /**
      * Test {@link Complex#equals(Object)}. It should be consistent with
-     * {@link Arrays#equals(double[], double[])} called using the components 
of two complex numbers.
+     * {@link Arrays#equals(double[], double[])} called using the components 
of two
+     * complex numbers.
      */
     @Test
     public void testEqualsIsConsistentWithArraysEquals() {
         // Explicit check of the cases documented in the Javadoc:
-        assertEqualsIsConsistentWithArraysEquals(
-                Complex.ofCartesian(Double.NaN, 0.0),
-                Complex.ofCartesian(Double.NaN, 1.0), "NaN real and different 
non-NaN imaginary");
-        assertEqualsIsConsistentWithArraysEquals(
-                Complex.ofCartesian(0.0, Double.NaN),
-                Complex.ofCartesian(1.0, Double.NaN), "Different non-NaN real 
and NaN imaginary");
-        assertEqualsIsConsistentWithArraysEquals(
-                Complex.ofCartesian(0.0, 0.0),
-                Complex.ofCartesian(-0.0, 0.0), "Different real zeros");
-        assertEqualsIsConsistentWithArraysEquals(
-                Complex.ofCartesian(0.0, 0.0),
-                Complex.ofCartesian(0.0, -0.0), "Different imaginary zeros");
+        
assertEqualsIsConsistentWithArraysEquals(Complex.ofCartesian(Double.NaN, 0.0),
+            Complex.ofCartesian(Double.NaN, 1.0), "NaN real and different 
non-NaN imaginary");
+        assertEqualsIsConsistentWithArraysEquals(Complex.ofCartesian(0.0, 
Double.NaN),
+            Complex.ofCartesian(1.0, Double.NaN), "Different non-NaN real and 
NaN imaginary");
+        assertEqualsIsConsistentWithArraysEquals(Complex.ofCartesian(0.0, 
0.0), Complex.ofCartesian(-0.0, 0.0),
+            "Different real zeros");
+        assertEqualsIsConsistentWithArraysEquals(Complex.ofCartesian(0.0, 
0.0), Complex.ofCartesian(0.0, -0.0),
+            "Different imaginary zeros");
 
         // Test some values of edge cases
-        final double[] values = {
-            Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 
-1, 0, 1
-        };
+        final double[] values = {Double.NaN, Double.NEGATIVE_INFINITY, 
Double.POSITIVE_INFINITY, -1, 0, 1};
         final ArrayList<Complex> list = createCombinations(values);
 
         for (final Complex c : list) {
@@ -1353,9 +1363,7 @@ public class ComplexTest {
     @Test
     public void testEqualsWithDifferentNaNs() {
         // Test some NaN combinations
-        final double[] values = {
-            Double.NaN, 0, 1
-        };
+        final double[] values = {Double.NaN, 0, 1};
         final ArrayList<Complex> list = createCombinations(values);
 
         // Is the all-vs-all comparison only the exact same values should be 
equal, e.g.
@@ -1374,34 +1382,32 @@ public class ComplexTest {
     }
 
     /**
-     * Test the two complex numbers with {@link Complex#equals(Object)} and 
check the result
-     * is consistent with {@link Arrays#equals(double[], double[])}.
+     * Test the two complex numbers with {@link Complex#equals(Object)} and 
check the
+     * result is consistent with {@link Arrays#equals(double[], double[])}.
      *
      * @param c1 the first complex
      * @param c2 the second complex
      * @param msg the message to append to an assertion error
      */
     private static void assertEqualsIsConsistentWithArraysEquals(Complex c1, 
Complex c2, String msg) {
-        final boolean expected = Arrays.equals(new double[]{c1.getReal(), 
c1.getImaginary()},
-                                               new double[]{c2.getReal(), 
c2.getImaginary()});
+        final boolean expected = Arrays.equals(new double[] {c1.getReal(), 
c1.getImaginary()},
+            new double[] {c2.getReal(), c2.getImaginary()});
         final boolean actual = c1.equals(c2);
-        Assertions.assertEquals(expected, actual, () -> String.format(
-            "equals(Object) is not consistent with Arrays.equals: %s. %s vs 
%s", msg, c1, c2));
+        Assertions.assertEquals(expected, actual,
+            () -> String.format("equals(Object) is not consistent with 
Arrays.equals: %s. %s vs %s", msg, c1, c2));
     }
 
     /**
      * Test {@link Complex#hashCode()}. It should be consistent with
      * {@link Arrays#hashCode(double[])} called using the components of the 
complex number
-     * and fulfil the contract of {@link Object#hashCode()},
-     * i.e. objects with different hash codes are {@code false} for {@link 
Object#equals(Object)}.
+     * and fulfil the contract of {@link Object#hashCode()}, i.e. objects with 
different
+     * hash codes are {@code false} for {@link Object#equals(Object)}.
      */
     @Test
     public void testHashCode() {
         // Test some values match Arrays.hashCode(double[])
-        final double[] values = {
-            Double.NaN, Double.NEGATIVE_INFINITY, -3.45, -1, -0.0, 0.0,
-            Double.MIN_VALUE, 1, 3.45, Double.POSITIVE_INFINITY
-        };
+        final double[] values = {Double.NaN, Double.NEGATIVE_INFINITY, -3.45, 
-1, -0.0, 0.0, Double.MIN_VALUE, 1, 3.45,
+            Double.POSITIVE_INFINITY};
         final ArrayList<Complex> list = createCombinations(values);
 
         final String msg = "'equals' not compatible with 'hashCode'";
@@ -1413,7 +1419,8 @@ public class ComplexTest {
             final int hash = c.hashCode();
             Assertions.assertEquals(expected, hash, "hashCode does not match 
Arrays.hashCode({re, im})");
 
-            // Test a copy has the same hash code, i.e. is not 
System.identityHashCode(Object)
+            // Test a copy has the same hash code, i.e. is not
+            // System.identityHashCode(Object)
             final Complex copy = Complex.ofCartesian(real, imag);
             Assertions.assertEquals(hash, copy.hashCode(), "Copy hash code is 
not equal");
 
@@ -1441,11 +1448,13 @@ public class ComplexTest {
     /**
      * Specific test that different representations of zero satisfy the 
contract of
      * {@link Object#hashCode()}: if two objects have different hash codes, 
"equals" must
-     * return false. This is an issue with using {@link 
Double#hashCode(double)} to create hash
-     * codes and {@code ==} for equality when using different representations 
of zero:
-     * Double.hashCode(-0.0) != Double.hashCode(0.0) but -0.0 == 0.0 is {@code 
true}.
+     * return false. This is an issue with using {@link 
Double#hashCode(double)} to create
+     * hash codes and {@code ==} for equality when using different 
representations of
+     * zero: Double.hashCode(-0.0) != Double.hashCode(0.0) but -0.0 == 0.0 is
+     * {@code true}.
      *
-     * @see <a 
href="https://issues.apache.org/jira/projects/MATH/issues/MATH-1118";>MATH-1118</a>
+     * @see <a
+     * 
href="https://issues.apache.org/jira/projects/MATH/issues/MATH-1118";>MATH-1118</a>
      */
     @Test
     public void testHashCodeWithDifferentZeros() {
@@ -1483,9 +1492,10 @@ public class ComplexTest {
     }
 
     /**
-     * Perform the smallest change to the value. This returns the next double 
value adjacent to
-     * d in the direction of infinity. Edge cases: if already infinity then 
return the next closest
-     * in the direction of negative infinity; if nan then return 0.
+     * Perform the smallest change to the value. This returns the next double 
value
+     * adjacent to d in the direction of infinity. Edge cases: if already 
infinity then
+     * return the next closest in the direction of negative infinity; if nan 
then return
+     * 0.
      *
      * @param x the x
      * @return the new value
@@ -1494,9 +1504,7 @@ public class ComplexTest {
         if (Double.isNaN(x)) {
             return 0;
         }
-        return x == Double.POSITIVE_INFINITY ?
-                Math.nextDown(x) :
-                Math.nextUp(x);
+        return x == Double.POSITIVE_INFINITY ? Math.nextDown(x) : 
Math.nextUp(x);
     }
 
     @Test
@@ -1506,22 +1514,23 @@ public class ComplexTest {
         // CHECKSTYLE: stop Regexp
         System.out.println(">>testJava()");
         // MathTest#testExpSpecialCases() checks the following:
-        // Assert.assertEquals("exp of -infinity should be 0.0", 0.0, 
Math.exp(Double.NEGATIVE_INFINITY), Precision.EPSILON);
+        // Assert.assertEquals("exp of -infinity should be 0.0", 0.0,
+        // Math.exp(Double.NEGATIVE_INFINITY), Precision.EPSILON);
         // Let's check how well Math works:
         System.out.println("Math.exp=" + Math.exp(Double.NEGATIVE_INFINITY));
-        final String[] props = {
-            "java.version", //    Java Runtime Environment version
+        final String[] props = {"java.version", // Java Runtime Environment 
version
             "java.vendor", // Java Runtime Environment vendor
-            "java.vm.specification.version", //   Java Virtual Machine 
specification version
-            "java.vm.specification.vendor", //    Java Virtual Machine 
specification vendor
-            "java.vm.specification.name", //  Java Virtual Machine 
specification name
+            "java.vm.specification.version", // Java Virtual Machine 
specification version
+            "java.vm.specification.vendor", // Java Virtual Machine 
specification vendor
+            "java.vm.specification.name", // Java Virtual Machine 
specification name
             "java.vm.version", // Java Virtual Machine implementation version
-            "java.vm.vendor", //  Java Virtual Machine implementation vendor
-            "java.vm.name", //    Java Virtual Machine implementation name
-            "java.specification.version", //  Java Runtime Environment 
specification version
-            "java.specification.vendor", //   Java Runtime Environment 
specification vendor
+            "java.vm.vendor", // Java Virtual Machine implementation vendor
+            "java.vm.name", // Java Virtual Machine implementation name
+            "java.specification.version", // Java Runtime Environment 
specification
+                                          // version
+            "java.specification.vendor", // Java Runtime Environment 
specification vendor
             "java.specification.name", // Java Runtime Environment 
specification name
-            "java.class.version", //  Java class format version number
+            "java.class.version", // Java class format version number
         };
         for (final String t : props) {
             System.out.println(t + "=" + System.getProperty(t));
@@ -1627,6 +1636,7 @@ public class ComplexTest {
 
     /**
      * Test: computing <b>third roots</b> of z.
+     * 
      * <pre>
      * <code>
      * <b>z = -2 + 2 * i</b>
@@ -1645,18 +1655,19 @@ public class ComplexTest {
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
-        Assertions.assertEquals(1.0,                  
thirdRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(1.0,                  
thirdRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(1.0, thirdRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(1.0, thirdRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(-1.3660254037844386,  
thirdRootsOfZ[1].getReal(),      1.0e-5);
-        Assertions.assertEquals(0.36602540378443843,  
thirdRootsOfZ[1].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-1.3660254037844386, 
thirdRootsOfZ[1].getReal(), 1.0e-5);
+        Assertions.assertEquals(0.36602540378443843, 
thirdRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(0.366025403784439,    
thirdRootsOfZ[2].getReal(),      1.0e-5);
-        Assertions.assertEquals(-1.3660254037844384,  
thirdRootsOfZ[2].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0.366025403784439, thirdRootsOfZ[2].getReal(), 
1.0e-5);
+        Assertions.assertEquals(-1.3660254037844384, 
thirdRootsOfZ[2].getImaginary(), 1.0e-5);
     }
 
     /**
      * Test: computing <b>fourth roots</b> of z.
+     * 
      * <pre>
      * <code>
      * <b>z = 5 - 2 * i</b>
@@ -1676,21 +1687,22 @@ public class ComplexTest {
         // Returned Collection must not be empty!
         Assertions.assertEquals(4, fourthRootsOfZ.length);
         // test z_0
-        Assertions.assertEquals(1.5164629308487783,     
fourthRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(-0.14469266210702247,   
fourthRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(1.5164629308487783, 
fourthRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(-0.14469266210702247, 
fourthRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(0.14469266210702256,    
fourthRootsOfZ[1].getReal(),      1.0e-5);
-        Assertions.assertEquals(1.5164629308487783,     
fourthRootsOfZ[1].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0.14469266210702256, 
fourthRootsOfZ[1].getReal(), 1.0e-5);
+        Assertions.assertEquals(1.5164629308487783, 
fourthRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(-1.5164629308487783,    
fourthRootsOfZ[2].getReal(),      1.0e-5);
-        Assertions.assertEquals(0.14469266210702267,    
fourthRootsOfZ[2].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-1.5164629308487783, 
fourthRootsOfZ[2].getReal(), 1.0e-5);
+        Assertions.assertEquals(0.14469266210702267, 
fourthRootsOfZ[2].getImaginary(), 1.0e-5);
         // test z_3
-        Assertions.assertEquals(-0.14469266210702275,   
fourthRootsOfZ[3].getReal(),      1.0e-5);
-        Assertions.assertEquals(-1.5164629308487783,    
fourthRootsOfZ[3].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-0.14469266210702275, 
fourthRootsOfZ[3].getReal(), 1.0e-5);
+        Assertions.assertEquals(-1.5164629308487783, 
fourthRootsOfZ[3].getImaginary(), 1.0e-5);
     }
 
     /**
      * Test: computing <b>third roots</b> of z.
+     * 
      * <pre>
      * <code>
      * <b>z = 8</b>
@@ -1710,19 +1722,19 @@ public class ComplexTest {
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
-        Assertions.assertEquals(2.0,                
thirdRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(0.0,                
thirdRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(2.0, thirdRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(0.0, thirdRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(-1.0,               
thirdRootsOfZ[1].getReal(),      1.0e-5);
+        Assertions.assertEquals(-1.0, thirdRootsOfZ[1].getReal(), 1.0e-5);
         Assertions.assertEquals(1.7320508075688774, 
thirdRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(-1.0,               
thirdRootsOfZ[2].getReal(),      1.0e-5);
+        Assertions.assertEquals(-1.0, thirdRootsOfZ[2].getReal(), 1.0e-5);
         Assertions.assertEquals(-1.732050807568877, 
thirdRootsOfZ[2].getImaginary(), 1.0e-5);
     }
 
-
     /**
      * Test: computing <b>third roots</b> of z with real part 0.
+     * 
      * <pre>
      * <code>
      * <b>z = 2 * i</b>
@@ -1741,21 +1753,21 @@ public class ComplexTest {
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
-        Assertions.assertEquals(1.0911236359717216,      
thirdRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(0.6299605249474365,      
thirdRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(1.0911236359717216, 
thirdRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(0.6299605249474365, 
thirdRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(-1.0911236359717216,     
thirdRootsOfZ[1].getReal(),      1.0e-5);
-        Assertions.assertEquals(0.6299605249474365,      
thirdRootsOfZ[1].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-1.0911236359717216, 
thirdRootsOfZ[1].getReal(), 1.0e-5);
+        Assertions.assertEquals(0.6299605249474365, 
thirdRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(-2.3144374213981936E-16, 
thirdRootsOfZ[2].getReal(),      1.0e-5);
-        Assertions.assertEquals(-1.2599210498948732,     
thirdRootsOfZ[2].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-2.3144374213981936E-16, 
thirdRootsOfZ[2].getReal(), 1.0e-5);
+        Assertions.assertEquals(-1.2599210498948732, 
thirdRootsOfZ[2].getImaginary(), 1.0e-5);
     }
 
     /**
-     * Test: compute <b>third roots</b> using a negative argument
-     * to go clockwise around the unit circle. Fourth roots of one
-     * are taken in both directions around the circle using
-     * positive and negative arguments.
+     * Test: compute <b>third roots</b> using a negative argument to go 
clockwise around
+     * the unit circle. Fourth roots of one are taken in both directions 
around the circle
+     * using positive and negative arguments.
+     * 
      * <pre>
      * <code>
      * <b>z = 1</b>
@@ -1773,31 +1785,31 @@ public class ComplexTest {
         // The List holding all fourth roots
         Complex[] fourthRootsOfZ = z.nthRoot(4).toArray(new Complex[0]);
         // test z_0
-        Assertions.assertEquals(1,   fourthRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(0,   fourthRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(1, fourthRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(0,   fourthRootsOfZ[1].getReal(),      1.0e-5);
-        Assertions.assertEquals(1,   fourthRootsOfZ[1].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[1].getReal(), 1.0e-5);
+        Assertions.assertEquals(1, fourthRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(-1,  fourthRootsOfZ[2].getReal(),      1.0e-5);
-        Assertions.assertEquals(0,   fourthRootsOfZ[2].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-1, fourthRootsOfZ[2].getReal(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[2].getImaginary(), 1.0e-5);
         // test z_3
-        Assertions.assertEquals(0,   fourthRootsOfZ[3].getReal(),      1.0e-5);
-        Assertions.assertEquals(-1,  fourthRootsOfZ[3].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[3].getReal(), 1.0e-5);
+        Assertions.assertEquals(-1, fourthRootsOfZ[3].getImaginary(), 1.0e-5);
         // go clockwise around the unit circle using negative argument
         fourthRootsOfZ = z.nthRoot(-4).toArray(new Complex[0]);
         // test z_0
-        Assertions.assertEquals(1,   fourthRootsOfZ[0].getReal(),      1.0e-5);
-        Assertions.assertEquals(0,   fourthRootsOfZ[0].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(1, fourthRootsOfZ[0].getReal(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[0].getImaginary(), 1.0e-5);
         // test z_1
-        Assertions.assertEquals(0,   fourthRootsOfZ[1].getReal(),      1.0e-5);
-        Assertions.assertEquals(-1,  fourthRootsOfZ[1].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[1].getReal(), 1.0e-5);
+        Assertions.assertEquals(-1, fourthRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
-        Assertions.assertEquals(-1,  fourthRootsOfZ[2].getReal(),      1.0e-5);
-        Assertions.assertEquals(0,   fourthRootsOfZ[2].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(-1, fourthRootsOfZ[2].getReal(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[2].getImaginary(), 1.0e-5);
         // test z_3
-        Assertions.assertEquals(0,   fourthRootsOfZ[3].getReal(),      1.0e-5);
-        Assertions.assertEquals(1,   fourthRootsOfZ[3].getImaginary(), 1.0e-5);
+        Assertions.assertEquals(0, fourthRootsOfZ[3].getReal(), 1.0e-5);
+        Assertions.assertEquals(1, fourthRootsOfZ[3].getImaginary(), 1.0e-5);
     }
 
     @Test
@@ -1811,6 +1823,7 @@ public class ComplexTest {
             Assertions.assertTrue(Double.isNaN(c.getImaginary()));
         }
     }
+
     @Test
     public void testNthRootInf() {
         final int n = 3;
@@ -1882,8 +1895,8 @@ public class ComplexTest {
 
     @Test
     public void testParse() {
-        final double[] parts = {Double.NEGATIVE_INFINITY, -1, -0.0, 0.0, 1, 
Math.PI,
-                                Double.POSITIVE_INFINITY, Double.NaN};
+        final double[] parts = {Double.NEGATIVE_INFINITY, -1, -0.0, 0.0, 1, 
Math.PI, Double.POSITIVE_INFINITY,
+            Double.NaN};
         for (final double x : parts) {
             for (final double y : parts) {
                 final Complex z = Complex.ofCartesian(x, y);
@@ -2004,4 +2017,26 @@ public class ComplexTest {
         Assertions.assertEquals(0.54930614433405489, c.getReal());
         Assertions.assertEquals(1.5707963267948966, c.getImaginary());
     }
+
+    @Test
+    public void testAtanhAssumptions() {
+        // Compute the same constants used by atanh
+        final double safeUpper = Math.sqrt(Double.MAX_VALUE) / 2;
+        final double safeLower = Math.sqrt(Double.MIN_NORMAL) * 2;
+
+        // Can we assume (1+x) = x when x is large
+        Assertions.assertEquals(safeUpper, 1 + safeUpper);
+        // Can we assume (1-x) = -x when x is large
+        Assertions.assertEquals(-safeUpper, 1 - safeUpper);
+        // Can we assume (y^2/x) = 0 when y is small and x is large
+        Assertions.assertEquals(0, safeLower * safeLower / safeUpper);
+        // Can we assume (1-x)^2/y + y = y when x <= 1. Try with x = 0.
+        Assertions.assertEquals(safeUpper, 1 / safeUpper + safeUpper);
+        // Can we assume (4+y^2) = 4 when y is small
+        Assertions.assertEquals(4, 4 + safeLower * safeLower);
+        // Can we assume (1-x)^2 = 1 when x is small
+        Assertions.assertEquals(1, (1 - safeLower) * (1 - safeLower));
+        // Can we assume 1 - y^2 = 1 when y is small
+        Assertions.assertEquals(1, 1 - safeLower * safeLower);
+    }
 }

Reply via email to