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/10 14:59:35 UTC
[commons-numbers] 05/05: Improve CReferenceTest equality assertions
and debug reporting.
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 e135bae831ace9d237a12af261abc4ff616bd41a
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Dec 10 14:59:25 2019 +0000
Improve CReferenceTest equality assertions and debug reporting.
Changed a few max ULPs for some of the tests.
---
.../commons/numbers/complex/CReferenceTest.java | 100 ++++++++++++++++-----
1 file changed, 78 insertions(+), 22 deletions(-)
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
index d122235..caddc73 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
@@ -37,6 +37,11 @@ import java.util.function.UnaryOperator;
* ISO/IEC 9899 - Programming languages - C</a>
*/
public class CReferenceTest {
+ /** Positive zero bits. */
+ private static final long POSITIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(+0.0);
+ /** Negative zero bits. */
+ private static final long NEGATIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(-0.0);
+
/**
* The maximum units of least precision (ULPs) allowed between values.
* This is a global setting used to override individual test settings for ULPs as follows:
@@ -50,26 +55,42 @@ public class CReferenceTest {
* setting takes precedence.
* </ul>
*
- * <p>During testing if the difference between an expected and actual result is greater in
- * magnitude than the current ULPS then this is considered an error. If the maximum ULPs is
- * positive then an assertion error is raised. If negative then the error is printed to
- * System out. This allows reporting of large deviations between the library and the
- * reference data.
+ * <p>During testing the difference between an expected and actual result is specified by the
+ * count of numbers in the range between them lower end exclusive and upper end inclusive.
+ * Two equal numbers have a count of 0. The next adjacent value has a count of 1.
+ *
+ * <p>If the configured ULPs is positive then the test is
+ * asserted using: {@code delta <= maxUlps}.
+ *
+ * <p>If the configured ULPs is negative the test is asserted using:
+ * {@code delta <= (|maxUlps|-1)}. This allows setting a ULPs of -1 to indicate
+ * maximum ULPs = 0 but flagging the assertion for special processing.
+ *
+ * <p>If the maximum ULPs is positive then an assertion error is raised.
+ * If negative then the error is printed to System out. This allows reporting of large
+ * deviations between the library and the reference data.
*
* <p>In a standard use-case all tests will have a configured positive maximum ULPs to
* pass the current test data. The global setting can be set to a negative value to allow
- * reporting of errors larger in magnitude to the console.
+ * reporting of errors larger in magnitude to the console. Setting -1 will output all
+ * differences. Setting -2 will output only those with a value between the two numbers,
+ * i.e. the numbers are not the same to floating point roundoff.
*
* <p>Setting the global maximum ULPs to negative has the second effect of loading all
- * data that has been flagged in data files. Otherwise this data is ignored by testing and
- * printed to System out.
+ * data that has been flagged in data files using the {@code ;} character.
+ * Otherwise this data is ignored by testing and printed to System out.
*/
private static long globalMaxUlps = 0;
+ /** Set this to true to report all deviations to System out when the maximum ULPs is negative. */
+ private static boolean reportAllDeviations = false;
+
/**
* Assert the two numbers are equal within the provided units of least precision.
* The maximum count of numbers allowed between the two values is {@code maxUlps - 1}.
*
+ * <p>Numbers must have the same sign. Thus -0.0 and 0.0 are never equal.
+ *
* @param msg the failure message
* @param expected the expected
* @param actual the actual
@@ -78,18 +99,49 @@ public class CReferenceTest {
private static void assertEquals(Supplier<String> msg, double expected, double actual, long maxUlps) {
final long e = Double.doubleToLongBits(expected);
final long a = Double.doubleToLongBits(actual);
- final long delta = Math.abs(e - a);
- if (delta > Math.abs(maxUlps)) {
- // DEBUG:
- if (maxUlps < 0) {
- // CHECKSTYLE: stop Regex
- System.out.printf("%s: expected <%s> != actual <%s> (ulps=%d)%n",
- msg.get(), expected, actual, delta);
- // CHECKSTYLE: resume Regex
+
+ // Code adapted from Precision#equals(double, double, int) so we maintain the delta
+ // for the message.
+
+ long delta;
+ boolean equal;
+ if (e == a) {
+ // Binary equal
+ equal = true;
+ delta = 0;
+ } else if ((a ^ e) < 0L) {
+ // Opposite signs are never equal.
+ equal = false;
+ // The difference is the count of numbers between each and zero.
+ // This may overflow but we report it using an unsigned formatter.
+ if (a < e) {
+ delta = (e - POSITIVE_ZERO_DOUBLE_BITS) + (a - NEGATIVE_ZERO_DOUBLE_BITS) + 1;
} else {
- Assertions.fail(String.format("%s: expected <%s> != actual <%s> (ulps=%d)",
- msg.get(), expected, actual, delta));
+ delta = (a - POSITIVE_ZERO_DOUBLE_BITS) + (e - NEGATIVE_ZERO_DOUBLE_BITS) + 1;
}
+ } else {
+ delta = Math.abs(e - a);
+ // Allow input of a negative maximum ULPs
+ equal = delta <= ((maxUlps < 0) ? (-maxUlps - 1) : maxUlps);
+ }
+
+ // DEBUG:
+ if (maxUlps < 0) {
+ // CHECKSTYLE: stop Regex
+ if (!equal) {
+ System.out.printf("%s: expected <%s> != actual <%s> (ulps=%s)%n",
+ msg.get(), expected, actual, Long.toUnsignedString(delta));
+ } else if (reportAllDeviations) {
+ System.out.printf("%s: expected <%s> == actual <%s> (ulps=0)%n",
+ msg.get(), expected, actual);
+ }
+ // CHECKSTYLE: resume Regex
+ return;
+ }
+
+ if (!equal) {
+ Assertions.fail(String.format("%s: expected <%s> != actual <%s> (ulps=%s)",
+ msg.get(), expected, actual, Long.toUnsignedString(delta)));
}
}
@@ -100,6 +152,8 @@ public class CReferenceTest {
* precision. The maximum count of numbers allowed between the two values is
* {@code maxUlps - 1}.
*
+ * <p>Numbers must have the same sign. Thus -0.0 and 0.0 are never equal.
+ *
* @param c Input number.
* @param name the operation name
* @param operation the operation
@@ -121,6 +175,8 @@ public class CReferenceTest {
* precision. The maximum count of numbers allowed between the two values is
* {@code maxUlps - 1}.
*
+ * <p>Numbers must have the same sign. Thus -0.0 and 0.0 are never equal.
+ *
* @param c1 First number.
* @param c2 Second number.
* @param name the operation name
@@ -222,13 +278,13 @@ public class CReferenceTest {
@Test
public void testAsinh() {
// Odd function: negative real cases defined by positive real cases
- assertOperation("asinh", Complex::asinh, 2);
+ assertOperation("asinh", Complex::asinh, 1);
}
@Test
public void testAtanh() {
// Odd function: negative real cases defined by positive real cases
- assertOperation("atanh", Complex::atanh, 26);
+ assertOperation("atanh", Complex::atanh, 17);
}
@Test
@@ -271,11 +327,11 @@ public class CReferenceTest {
@Test
public void testDivide() {
- assertBiOperation("divide", Complex::divide, 0);
+ assertBiOperation("divide", Complex::divide, 7);
}
@Test
public void testPowComplex() {
- assertBiOperation("pow", Complex::pow, 17);
+ assertBiOperation("pow", Complex::pow, 9);
}
}