| the Compartmented Robust Posix C++ Unit Test system | hosted by |
|---|
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>(2), 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>(10), float(mavg), avg);
}
int main(int argc, char *argv[])
{
return crpcut::run(argc, argv);
}
fails one test:
FAILED: too_narrow
phase="running" --------------------------------------------------------------
/home/bjorn/devel/crpcut/doc-src/samples/ulps_diff.cpp:56
ASSERT_PRED(crpcut::match<crpcut::ulps_diff>(2), float(mavg), avg)
param1 = 149.833
param2 = 149.833
crpcut::match<crpcut::ulps_diff>(2) :
Max allowed diff = 2 ULPS
Actual diff = 5 ULPS
-------------------------------------------------------------------------------
===============================================================================
Total 2 test cases selected
UNTESTED : 0
PASSED : 1
FAILED : 1
See also crpcut::abs_diff and crpcut::relative_diff for alternative floating point number matching methods.