aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2022-01-12 14:38:51 +0100
committerAaron Rossetto <aaron.rossetto@ni.com>2022-02-04 13:16:00 -0600
commit3e496cbda1d809d2ca15f69cfa231424bf47179f (patch)
tree1f497818a2f5731c1a40dd951abcd5f0091fa63d /host/tests
parent559df2e457c80364f5ce6acec27f3d16bc724c8c (diff)
downloaduhd-3e496cbda1d809d2ca15f69cfa231424bf47179f.tar.gz
uhd-3e496cbda1d809d2ca15f69cfa231424bf47179f.tar.bz2
uhd-3e496cbda1d809d2ca15f69cfa231424bf47179f.zip
math: fp_compare: Adapt fp_compare_epsilon API to actual use
UHD had an issue where the design of fp_compare_epsilon and its usage differed. In fact, the *only* usage of fp_compare_epsilon outside of unit tests was to do a fuzzy frequency comparison, and it always took a form like this: ```cpp // The argument EPSILON may be implied, i.e., using the default if (fp_compare_epsilon<double>(test_freq, EPSILON) < boundary_freq) { // ... } ``` However, the API of fp_compare_epsilon was such that it would apply DOUBLE_PRECISION_EPSILON to part of the frequency comparison, thus rendering the argument EPSILON obsolete. When the default EPSILON was used, this was OK, but only when the floating point type of fp_compare_epsilon<> was `double`, and not `float`. As an example, consider the following: ``` if (fp_compare_epsilon<double>(1e9 + x, LITTLE_EPSILON) == 1e9) { // .... } double BIG_EPSILON = x * 10; if (fp_compare_epsilon<double>(1e9 + x, BIG_EPSILON) == 1e9) { // .... } ``` If you expect the second comparison to pass even if the first failed, then you are not alone. However, that's not what UHD would do. Because of the aforementioned behaviour, it would use DOUBLE_PRECISION_EPSILON for the right hand comparison, which would fail again. Instead of fixing the instances of fp_compare_epsilon throughout UHD, this patch changes the comparison algorithm from "very close with tolerance epsilon" to "close enough with tolerance epsilon". This requires only one side to be close to the other, using its own epsilon, so the aforementioned example would always pass on the second check. However, this exposed a second bug in fp_compare_epsilon. For greater-/less-than comparisons, it would use epsilon like a delta value, i.e., it would check if a + epsilon < b - epsilon That means that if a < b, but (b-a) < 2*epsilon, this check would return "false", i.e., it would report that a >= b, which is incorrect. These operators are now changed such that they first check equality of a and b using the algorithm described in the code, and then compare the values of a and b (ignoring epsilon) directly. A unit test for this case was added.
Diffstat (limited to 'host/tests')
-rw-r--r--host/tests/fp_compare_epsilon_test.cpp15
1 files changed, 15 insertions, 0 deletions
diff --git a/host/tests/fp_compare_epsilon_test.cpp b/host/tests/fp_compare_epsilon_test.cpp
index 0c2a7f1cb..3aa973d3e 100644
--- a/host/tests/fp_compare_epsilon_test.cpp
+++ b/host/tests/fp_compare_epsilon_test.cpp
@@ -75,6 +75,8 @@ BOOST_AUTO_TEST_CASE(float_equality_operators)
fp_compare_epsilon<float>(alpha._value + uhd::math::SINGLE_PRECISION_EPSILON);
BOOST_CHECK(not(alpha == charlie));
BOOST_CHECK(not(alpha == float(alpha._value + uhd::math::SINGLE_PRECISION_EPSILON)));
+
+ BOOST_CHECK(fp_compare_epsilon<float>(0.0) == 0.0);
}
BOOST_AUTO_TEST_CASE(double_equality_operators)
@@ -90,6 +92,8 @@ BOOST_AUTO_TEST_CASE(double_equality_operators)
fp_compare_epsilon<double>(alpha._value + uhd::math::DOUBLE_PRECISION_EPSILON);
BOOST_CHECK(not(alpha == charlie));
BOOST_CHECK(not(alpha == double(alpha._value + uhd::math::DOUBLE_PRECISION_EPSILON)));
+
+ BOOST_CHECK(fp_compare_epsilon<double>(0.0) == 0.0);
}
BOOST_AUTO_TEST_CASE(float_inequality_operators)
@@ -126,6 +130,8 @@ BOOST_AUTO_TEST_CASE(float_lessthan_operators)
BOOST_CHECK(not(alpha < charlie));
BOOST_CHECK(not(alpha < float(alpha._value - 1.2f)));
+
+ BOOST_CHECK(fp_compare_epsilon<float>(-0.1) < 0.0f);
}
BOOST_AUTO_TEST_CASE(double_lessthan_operators)
@@ -143,6 +149,11 @@ BOOST_AUTO_TEST_CASE(double_lessthan_operators)
BOOST_CHECK(not(alpha < charlie));
BOOST_CHECK(not(alpha < double(alpha._value - 1.0012)));
+
+ fp_compare_epsilon<double> foxtrot(1.0, 0.001);
+ BOOST_CHECK(foxtrot < 1.0015);
+
+ BOOST_CHECK(fp_compare_epsilon<double>(-0.1) < 0.0);
}
BOOST_AUTO_TEST_CASE(float_lessthanequals_operators)
@@ -159,6 +170,8 @@ BOOST_AUTO_TEST_CASE(float_lessthanequals_operators)
BOOST_CHECK(charlie <= alpha);
BOOST_CHECK(float(alpha._value - 1.2) <= alpha);
+
+ BOOST_CHECK(fp_compare_epsilon<double>(-0.01) < 0.0);
}
BOOST_AUTO_TEST_CASE(double_lessthanequals_operators)
@@ -209,6 +222,8 @@ BOOST_AUTO_TEST_CASE(double_greaterthan_operators)
BOOST_CHECK(not(alpha > charlie));
BOOST_CHECK(not(alpha > double(alpha._value + 0.0012)));
+
+ BOOST_CHECK(fp_compare_epsilon<double>(0.01) > 0.0);
}
BOOST_AUTO_TEST_CASE(float_greaterthanequals_operators)