diff --git a/Test/TestChecksum.hh b/Test/TestChecksum.hh
index e0b2d90268a3d40e3ed9dd400c0a1ba6205a5d35..87984e84a5e59d80ebc2371711240d2e419dce3b 100644
--- a/Test/TestChecksum.hh
+++ b/Test/TestChecksum.hh
@@ -1,4 +1,4 @@
-// (C) Copyright 2021 by Autodesk, Inc.
+// (C) Copyright 2022 by Autodesk, Inc.
 
 #ifndef BASE_TESTCHECKSUM_HH_INCLUDED
 #define BASE_TESTCHECKSUM_HH_INCLUDED
@@ -44,9 +44,9 @@ public:
   enum Type
   {
     EQUAL,      // result is bitwise identical
+    NEGLIGIBLE, // result is negligibly different
     UNKNOWN,    // non-negligible difference, but of unknown quality
     IMPROVED,   // result is better
-    NEGLIGIBLE, // result is negligibly different
     SUSPICIOUS, // result is different, and the new result might be worse
     REGRESSED,  // result is worse
     WORKED,     // result works now, but used to fail
@@ -55,8 +55,8 @@ public:
 
   static const char* type_text(const Type _type)
   {
-    static const char dscr[][32] = {"EQUAL", "UNKNOWN", "IMPROVED",
-        "NEGLIGIBLE", "SUSPICIOUS", "REGRESSED", "WORKED", "FAILED"};
+    static const char dscr[][32] = {"EQUAL", "NEGLIGIBLE", "UNKNOWN",
+        "IMPROVED", "SUSPICIOUS", "REGRESSED", "WORKED", "FAILED"};
     return dscr[_type];
   }
 
diff --git a/Test/TestChecksumNumberT.hh b/Test/TestChecksumNumberT.hh
index a556ab995bac4a29685a240b7338da016e33362b..c0433d4eddd02b34935a5ddda6e2886e69c09e6c 100644
--- a/Test/TestChecksumNumberT.hh
+++ b/Test/TestChecksumNumberT.hh
@@ -1,21 +1,25 @@
-// (C) Copyright 2021 by Autodesk, Inc.
+// (C) Copyright 2022 by Autodesk, Inc.
 
-#ifndef BASE_CHECKSUMLOGVALUET_HH_INCLUDE
-#define BASE_CHECKSUMLOGVALUET_HH_INCLUDE
+#ifndef BASE_TESTCHECKSUMNUMBERT_HH_INCLUDED
+#define BASE_TESTCHECKSUMNUMBERT_HH_INCLUDED
 
 #include <Base/Test/TestChecksum.hh>
 
 #ifdef TEST_ON
+
 #include <cmath>
 #include <sstream>
+#include <type_traits>
 
-namespace Test {
-namespace Checksum {
+namespace Test
+{
+namespace Checksum
+{
 
-/*! Default implementation of a comparison class for ValueT.
+/*! Comparison class using opeartor== of ValueT.
 */
 template <typename ValueT>
-struct DefaultCompareT
+struct EqualityCompareT
 {
   bool same(const ValueT& _a, const ValueT& _b) const { return _a == _b; }
 };
@@ -29,21 +33,68 @@ struct NoCompareT
 };
 
 
+enum class ToleranceType
+{
+  ABSOLUTE,
+  RELATIVE
+};
+
+enum
+{
+  DUMMY_EXPONENT = 1234
+};
+
 /*!
-Utility class to compare double with a tolerance. Can be used to redefine the
-default compare class in class ValueT.
+Utility class to compare values with a tolerance. Tolerance is specified via the
+template argument as 10^EXPONENT. If RELATIVE is true, the difference is divided
+by the right (new) value before comparison.
 */
-struct DoubleCompare
+template <typename ScalarT, int EXPONENT,
+    ToleranceType TOLERANCE_TYPE = ToleranceType::ABSOLUTE>
+struct TolerantCompareT
 {
-  DoubleCompare(double _tol = 1e-12) : tol_(_tol) {}
-  bool same(const double& _a, const double& _b) const
+
+  static_assert(EXPONENT != DUMMY_EXPONENT,
+      "For floating point checksums, please explicitly define a comparison "
+      "class, e.g. this TolerantCompareT with an exponent suitable for your "
+      "checksum.");
+  static_assert(
+      EXPONENT <= std::numeric_limits<ScalarT>::max_exponent10 ||
+          EXPONENT == DUMMY_EXPONENT, // disable assertion for default exponent
+      "Exponent too large");
+  static_assert(EXPONENT >= std::numeric_limits<ScalarT>::min_exponent10,
+      "Exponent too small");
+
+  bool same(const ScalarT& _a, const ScalarT& _b) const
   {
-    return std::fabs(_a - _b) <= tol_;
+    static const auto TOLERANCE = std::pow(10, EXPONENT);
+
+    // Prevent division by zero
+    if constexpr (TOLERANCE_TYPE == ToleranceType::RELATIVE)
+    {
+      if (_b == 0)
+        return _a == _b;
+    }
+
+    double diff = std::fabs(_a - _b);
+
+    if constexpr (TOLERANCE_TYPE == ToleranceType::RELATIVE)
+      diff /= _b;
+
+    return diff <= TOLERANCE;
   }
-private:
-  double tol_;
 };
 
+// The default Compare type for ValueT. For integral types exact equality is
+// checked. For floating point type TolerantCompare is used which actually
+// generates a compile error and asks the developer to choose a meaningful
+// threshold.
+template <typename ValueT>
+using DefaultCompareT = std::conditional_t<   // if
+    std::is_floating_point_v<ValueT>,         // ValueT is floating point
+    TolerantCompareT<ValueT, DUMMY_EXPONENT>, // use TolerantCompareT
+    EqualityCompareT<ValueT>>;                // else use EqualityCompare
+
 /*!
 Generic checksum class to record and compare a value of a certain type.
 */
@@ -71,11 +122,13 @@ protected:
     // TODO: multiple comparisons, can we use just one?
     if (val_new == val_old) // bitwise comparison
       return Difference::EQUAL;
-    if (comp_.same(val_old, val_new)) // tolerance comparison
-      return Difference::NEGLIGIBLE;
 
     Base::OStringStream diff;
     diff << (val_new - val_old);
+
+    if (comp_.same(val_old, val_new)) // tolerance comparison
+      return Difference(Difference::NEGLIGIBLE, diff.str);
+
     return Difference(Difference::UNKNOWN, diff.str);
   }
 
@@ -83,8 +136,14 @@ private:
   CompareT comp_; // Compare class.
 };
 
+template <typename ValueT, int EXPONENT,
+    ToleranceType TOLERANCE_TYPE = ToleranceType::ABSOLUTE>
+using TolerantNumberT =
+    NumberT<ValueT, TolerantCompareT<ValueT, EXPONENT, TOLERANCE_TYPE>>;
+
+
 }//namespace Checksum
 }//namespace Test
 
 #endif//TEST_ON
-#endif//BASE_CHECKSUMLOGVALUET_HH_INCLUDE
+#endif//BASE_TESTCHECKSUMNUMBERT_HH_INCLUDED
diff --git a/Test/TestReport.cc b/Test/TestReport.cc
index a7fec103b963deded059e5a10d79da13506c5448..9586e332066069fae3e7d42f0597cf3f1dec43df 100644
--- a/Test/TestReport.cc
+++ b/Test/TestReport.cc
@@ -1,4 +1,4 @@
-// (C) Copyright 2021 by Autodesk, Inc.
+// (C) Copyright 2022 by Autodesk, Inc.
 
 #ifdef TEST_ON
 
@@ -373,18 +373,35 @@ fs::path construct_diff_path(const fs::path& _root_left,
   return _root_right / diff_flnm;
 }
 
-// Add a border of asterisks around a string
-std::string add_border(const std::string& _message)
+
+// Add a border of asterisks around multiple strings. Each string is put on a
+// new line.
+std::string add_border(const std::vector<std::string>& _messages)
 {
-  const char ENDL = Base::ENDL;
-  std::string border = std::string(_message.size() + 4, '*');
+  using Base::ENDL;
+  const auto max_msg_size = std::max_element(_messages.begin(), _messages.end(),
+      [](const std::string& _a, const std::string& _b)
+      { return _a.size() < _b.size(); })->size();
+
+  const std::string border(max_msg_size + 4, '*');
 
   Base::OStringStream strm;
-  strm << ENDL << border << ENDL << "* " << _message << " *" << ENDL << border
-       << ENDL;
+  strm << ENDL << border << ENDL;
+  for (const auto& message : _messages)
+  {
+    const std::string padding(max_msg_size - message.size(), ' ');
+    strm << "* " << message << padding << " *" << ENDL;
+  }
+  strm << border << ENDL;
   return strm.str;
 }
 
+// Add a border of asterisks around a string
+std::string add_border(const std::string& _message)
+{
+  return add_border(std::vector<std::string>(1, _message));
+}
+
 // Namespace for functions that deal with updating and mirroring test
 // directories
 namespace Sync
@@ -474,7 +491,7 @@ ExitStatus make_comparison(const char* const _dir_left,
 
   // Compare the checksums produced by each test in the common set.
   size_t common_tests_nmbr = common_tests.size();
-  size_t diff_test_nmbr = 0, test_idx = 0;
+  size_t diff_test_nmbr = 0, negl_diff_test_nmbr = 0, test_idx = 0;
 
   if (!_show_progress)
     std::cout << "Comparing tests...";
@@ -508,6 +525,12 @@ ExitStatus make_comparison(const char* const _dir_left,
       // Count the number of tests for which differences were found
       ++diff_test_nmbr;
 
+      if (diff_stats.size() == 1 &&
+          diff_stats.find(Checksum::Difference::NEGLIGIBLE) != diff_stats.end())
+      {
+        ++negl_diff_test_nmbr; // all differences are negligible
+      }
+
       // If set to update or mirror the tests, empty the left-suite test output
       // directory and copy over the checksum report from the right-suite test
       // output directory.
@@ -526,11 +549,22 @@ ExitStatus make_comparison(const char* const _dir_left,
   }
   std::cout << "complete." << std::endl;
 
+  const auto test_string = [](size_t _nmbr)
+  {
+    auto res = std::to_string(_nmbr) + " TEST";
+    if (_nmbr != 1)
+      res += "S";
+    return res;
+  };
+
   // Print the comparison summary.
-  std::cout << add_border("COMPARISON HAS DETECTED DIFFERENCES IN " +
-                          std::to_string(diff_test_nmbr) + " TEST" +
-                          (diff_test_nmbr == 1 ? "" : "S") + ".")
-            << std::endl;
+  std::vector<std::string> messages;
+  messages.push_back("COMPARISON HAS DETECTED DIFFERENCES IN " +
+                     test_string(diff_test_nmbr) + ".");
+  messages.push_back(std::string("THE DIFFERENCES ARE NEGLIGIBLE IN ") +
+                     ((diff_test_nmbr == negl_diff_test_nmbr) ? "ALL " : "") +
+                     test_string(negl_diff_test_nmbr) + ".");
+  std::cout << add_border(messages) << std::endl;
 
   // Are we creating diffs?
   const bool create_diffs = _cot == COT_SHORT_DIFF || _cot == COT_FULL_DIFF;