Use new defaultRealTolerance() to stabilise some tests
authorMark Abraham <mark.j.abraham@gmail.com>
Wed, 20 Dec 2017 11:13:00 +0000 (22:13 +1100)
committerMark Abraham <mark.j.abraham@gmail.com>
Wed, 20 Dec 2017 12:35:44 +0000 (13:35 +0100)
The single-precision values in these tests sometimes failed to compare
equal with string-ified versions when the test was run from a
double-precision build on Windows. That difference may have originated
in how a rounding mode was implemented in different libraries, but
ultimately doesn't matter because the value should not be compared as
if it was computed in double precision.

Change-Id: I9b7c2b9409145cc579229f0866935754e3a9dcac

src/gromacs/energyanalysis/tests/legacyenergy.cpp
src/testutils/cmdlinetest.cpp
src/testutils/cmdlinetest.h
src/testutils/testasserts.h
src/testutils/tests/testasserts_tests.cpp

index dc2d6217ce4e84d41f3872b974c158d2fed19df9..7162fc1b179d3a77fc0f44419c5be00d172879de 100644 (file)
@@ -133,6 +133,11 @@ class EnergyTest : public CommandLineTestBase
             stdioHelper.redirectStringToStdin(stringForStdin);
             ASSERT_EQ(0, gmx_energy(cmdline.argc(), cmdline.argv()));
 
+            // All the .edr files used in the tests contain only
+            // single-precision values, so even from a
+            // double-precision build they should conform to
+            // tolerances suitable for single-precision values.
+            setDefaultTolerance(defaultFloatTolerance());
             checkOutputFiles();
         }
 };
index 5317d95b528505edf25368c722bc8ce9be3b09d4..2064b54c4efa65026e39593802677725c980e736 100644 (file)
@@ -455,6 +455,11 @@ TestReferenceChecker CommandLineTestBase::rootChecker()
     return impl_->data_.rootChecker();
 }
 
+void CommandLineTestBase::setDefaultTolerance(const FloatingPointTolerance &tolerance)
+{
+    impl_->data_.rootChecker().setDefaultTolerance(tolerance);
+}
+
 void CommandLineTestBase::testWriteHelp(ICommandLineModule *module)
 {
     StringOutputStream     stream;
index fc3fd4afaf0fb6f42214a4fcd8049604b066d1ea..3954a321d8b0e8b10b4c560de3a4539381d14751 100644 (file)
@@ -63,6 +63,7 @@ class ICommandLineOptionsModule;
 namespace test
 {
 
+class FloatingPointTolerance;
 class IFileMatcherSettings;
 class ITextBlockMatcherSettings;
 class TestFileManager;
@@ -443,7 +444,15 @@ class CommandLineTestBase : public ::testing::Test
          * file contents.
          */
         TestReferenceChecker rootChecker();
-
+        /*! \brief
+         * Sets the tolerance for floating-point comparisons.
+         *
+         * All following floating-point comparisons using the checker will use
+         * the new tolerance.
+         *
+         * Does not throw.
+         */
+        void setDefaultTolerance(const FloatingPointTolerance &tolerance);
         /*! \brief
          * Checks the output of writeHelp() against reference data.
          */
index c13c00ec569555c21931e3366ccb36a4bf300f82..c7ba7a4afe7589f5c35b396082bb9a537a736ea9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -486,6 +486,12 @@ relativeToleranceAsUlp(double magnitude, gmx_uint64_t ulpDiff)
     return relativeToleranceAsPrecisionDependentUlp(magnitude, ulpDiff, ulpDiff);
 }
 
+namespace
+{
+//! Default tolerance in ULPs for two floating-point values to compare equal.
+static gmx_uint64_t g_defaultUlpTolerance = 4;
+}
+
 /*! \brief
  * Returns the default tolerance for comparing `real` numbers.
  *
@@ -493,7 +499,23 @@ relativeToleranceAsUlp(double magnitude, gmx_uint64_t ulpDiff)
  */
 static inline FloatingPointTolerance defaultRealTolerance()
 {
-    return relativeToleranceAsUlp(1.0, 4);
+    return relativeToleranceAsUlp(1.0, g_defaultUlpTolerance);
+}
+
+
+/*! \brief
+ * Returns the default tolerance for comparing single-precision numbers when
+ * compared by \Gromacs built in either precision mode.
+ *
+ * This permits a checker compiled with any \Gromacs precision to compare
+ * equal or not in the same way.
+ *
+ * \related FloatingPointTolerance
+ */
+static inline FloatingPointTolerance defaultFloatTolerance()
+{
+    return relativeToleranceAsPrecisionDependentUlp
+               (1.0, g_defaultUlpTolerance, g_defaultUlpTolerance * (GMX_FLOAT_EPS / GMX_DOUBLE_EPS));
 }
 
 /*! \name Assertions for floating-point comparison
index 01e9d6146da17abb74e72d9d68dc94605c583e89..d7175eae5270ca20843a7b6a4caf428d20235f31 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2017, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -233,4 +233,38 @@ TEST(FloatingPointToleranceTest, RelativeToleranceAsUlp)
     EXPECT_FALSE(relativeToleranceAsUlp(1.0, 4).isWithin(dsmall2));
 }
 
+TEST(FloatingPointToleranceTest, DefaultFloatTolerance)
+{
+    using gmx::test::defaultFloatTolerance;
+
+    // Differences within 4 single-precision ULPs are within the tolerance
+    FloatingPointDifference fequal(1.0f, 1.0f);
+    FloatingPointDifference fulp4(1.0f, addUlps(1.0f, 4));
+    FloatingPointDifference fulp8(1.0f, addUlps(1.0f, 8));
+    FloatingPointDifference fsmall(0.1f, addUlps(1.0f, 2) - 0.9f);
+    FloatingPointDifference fsmall2(0.1f, addUlps(1.0f, 6) - 0.9f);
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(fequal));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(fulp4));
+    EXPECT_FALSE(defaultFloatTolerance().isWithin(fulp8));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(fsmall));
+    EXPECT_FALSE(defaultFloatTolerance().isWithin(fsmall2));
+
+    // Differences within 4 single-precision ULPs are still within the
+    // tolerance, even when expressed as double-precision values.
+    FloatingPointDifference dequal(1.0, 1.0);
+    FloatingPointDifference dulp4(1.0, addUlps(1.0, 4));
+    FloatingPointDifference dulp8(1.0, addUlps(1.0, 8));
+    FloatingPointDifference dulp4f(1.0, static_cast<double>(addUlps(1.0f, 4)));
+    FloatingPointDifference dulp8f(1.0, static_cast<double>(addUlps(1.0f, 8)));
+    FloatingPointDifference dsmallf(0.1, static_cast<double>(addUlps(1.0f, 2) - 0.9f));
+    FloatingPointDifference dsmall2f(0.1, static_cast<double>(addUlps(1.0f, 6) - 0.9f));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(dequal));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(dulp4));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(dulp8));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(dulp4f));
+    EXPECT_FALSE(defaultFloatTolerance().isWithin(dulp8f));
+    EXPECT_TRUE(defaultFloatTolerance().isWithin(dsmallf));
+    EXPECT_FALSE(defaultFloatTolerance().isWithin(dsmall2f));
+}
+
 } // namespace