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 2019/12/20 17:58:03 UTC
[commons-numbers] 12/30: Added atanh assumptions test to check the
safe upper and lower limits.
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 <ah...@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);
+ }
}