| 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.