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 Noncritical PASSED : 1 1 0 FAILED : 1 1 0
See also crpcut::abs_diff and crpcut::relative_diff for alternative floating point number matching methods.