the Compartmented Robust Posix C++ Unit Test system |
|
---|
Test that two floating point numbers do not differ by more than a fixed number of possibly representable values for the type.
Used in: Template parameter to
crpcut::match
<matcher>(...) in an
ASSERT_PRED(pred, ...)
check.
Verify that a
and b
do not differ by more than a fixed number of
“Units of Least Precision”. See
Cygnus
information on
comparing floating point numbers
for an introduction to ULPS. The two parameters a
and b
must have the same floating point type.
It is, optionally, possible to decide whether infinity is a valid
number (one ULPS higher than
std::numeric_limits<T>::max()
) by
by setting the second parameter to the constructor to one of
crpcut::include_inf
or
crpcut::exclude_inf
. By default
crpcut::exclude_inf
is assumed.
Caution | |
---|---|
ULPS diff only works for float and double, and is only tested on x86 and compatible architectures and is almost certain to fail horrendously on others. |
Example: the test program
#include <crpcut.hpp> #include <numeric> #include <limits> template <typename T> class moving_avg { public: moving_avg() : avg(T()), n(T()) {} moving_avg& operator+=(T t) { ++n; avg-= (avg - t)/n; return *this; } operator T() const { return avg; } private: T avg; T n; }; static const unsigned count = 300; TEST(too_narrow) { moving_avg<float> mavg; float sum = 0.0; for (unsigned n = 0; n < count; ++n) { mavg+= 1.0f/3 + float(n); sum+= 1.0f/3 + float(n); } float avg = sum/count; ASSERT_PRED(crpcut::match<crpcut::ulps_diff>(2U), float(mavg), avg); } TEST(close_enough) { moving_avg<float> mavg; float sum = 0.0; for (unsigned n = 0; n < count; ++n) { mavg+= 1.0f/3 + float(n); sum+= 1.0f/3 + float(n); } float avg = sum/count; ASSERT_PRED(crpcut::match<crpcut::ulps_diff>(10U), float(mavg), avg); } int main(int argc, char *argv[]) { return crpcut::run(argc, argv); }
fails one test:
FAILED!: too_narrow phase="running" -------------------------------------------------------------- samples/ulps_diff.cpp:56 ASSERT_PRED(crpcut::match<crpcut::ulps_diff>(2U), float(mavg), avg) param1 = 149.833 param2 = 149.833 for crpcut::match<crpcut::ulps_diff>(2U): Max allowed diff = 2 ULPS Actual diff = 5 ULPS ------------------------------------------------------------------------------- =============================================================================== 2 test cases selected Sum Critical Non-critical PASSED : 1 1 0 FAILED : 1 1 0
See also crpcut::abs_diff and crpcut::relative_diff for alternative floating point number matching methods.