scran_test_utils
Test utilities for libscran projects
Loading...
Searching...
No Matches
compare_almost_equal.hpp
Go to the documentation of this file.
1#ifndef SCRAN_TESTS_COMPARE_ALMOST_EQUAL_HPP
2#define SCRAN_TESTS_COMPARE_ALMOST_EQUAL_HPP
3
4#include <gtest/gtest.h>
5#include <cmath>
6
12namespace scran_tests {
13
21 double relative_tolerance = 1e-8;
22
26 double absolute_tolerance = 1e-15;
27
31 bool nan_equal = true;
32
36 bool report = true;
37};
38
55inline bool compare_almost_equal(double left, double right, const CompareAlmostEqualParameters& params) {
56 const auto message = [&]() -> void {
57 if (params.report) {
58 EXPECT_TRUE(false) << "mismatching floats (" << left << " versus " << right << ")";
59 }
60 };
61
62 if (std::isnan(left) || std::isnan(right)) {
63 if (std::isnan(left) != std::isnan(right) || !params.nan_equal) {
64 message();
65 return false;
66 } else {
67 return true;
68 }
69 }
70
71 if (left == right) {
72 return true;
73 }
74
75 // Use relative tolerance to check that we get a similar float.
76 // EXPECT_EQ and even EXPECT_DOUBLE_EQ tend to be a bit too stringent when numerical imprecision is expected.
77 // We define the relative difference as '|difference| / |mean|' of the two values, and check that this is below some acceptable error, in this case 1e-8.
78 //
79 // It's worth nothing that I spent a long time using EXPECT_FLOAT_EQ when I really should have been using EXPECT_DOUBLE_EQ.
80 // This would have implicitly used a relative threshold at the 8th significant figure, which is why it allowed tests to pass despite imprecision.
81 const double denom = std::abs(left + right) / 2;
82 double threshold = denom * params.relative_tolerance;
83
84 // 'relative difference < tol' is equivalent to '|difference| < threshold'.
85 // However, if '|mean|' is very small, we start to revert back to an exact equality test.
86 // This is not ideal - we DON'T want to fail the test if one value is zero and another is very slightly non-zero.
87 // So we need to ensure that the threshold doesn't get too small, by setting a lower bound similar to the machine epsilon.
88 // (That said, if we're dealing with lots of very-near-zero values, this function won't be appropriate as it'll consider them to be the same.)
89 if (threshold < params.absolute_tolerance) {
90 threshold = params.absolute_tolerance;
91 }
92 if (std::abs(left - right) > threshold) {
93 message();
94 return false;
95 }
96
97 return true;
98}
99
114template<class LeftContainer_, class RightContainer_>
115void compare_almost_equal_containers(const LeftContainer_& left, const RightContainer_& right, CompareAlmostEqualParameters params) {
116 auto n = left.size();
117 ASSERT_EQ(n, right.size());
118
119 params.report = false;
120 for (decltype(n) i = 0; i < n; ++i) {
121 if (!compare_almost_equal(left[i], right[i], params)) {
122 EXPECT_TRUE(false) << "mismatch in almost-equal floats at element " << i << " (expected " << left[i] << ", got " << right[i] << ")";
123 return;
124 }
125 }
126}
127
131// Back-compatibility.
132inline bool compare_almost_equal(double left, double right) {
133 return compare_almost_equal(left, right, {});
134}
135
136template<class Vector_>
137void compare_almost_equal(const Vector_& left, const Vector_& right, double tol = 1e-8) {
138 compare_almost_equal_containers(left, right, [&]{
139 CompareAlmostEqualParameters params;
140 params.relative_tolerance = tol;
141 return params;
142 }());
143}
148}
149
150#endif
Test utilites for libscran.
Definition compare_almost_equal.hpp:12
void compare_almost_equal_containers(const LeftContainer_ &left, const RightContainer_ &right, CompareAlmostEqualParameters params)
Definition compare_almost_equal.hpp:115
bool compare_almost_equal(double left, double right, const CompareAlmostEqualParameters &params)
Definition compare_almost_equal.hpp:55
Parameters for compare_almost_equal().
Definition compare_almost_equal.hpp:17
bool report
Definition compare_almost_equal.hpp:36
double absolute_tolerance
Definition compare_almost_equal.hpp:26
bool nan_equal
Definition compare_almost_equal.hpp:31
double relative_tolerance
Definition compare_almost_equal.hpp:21