areClose() tests and docs

This commit is contained in:
Pavel Kirienko 2014-08-29 01:25:55 +04:00
parent d4019da5ff
commit 8b73a68de8
2 changed files with 94 additions and 11 deletions

View File

@ -121,18 +121,24 @@ inline bool areCloseImplFirst(const L& left, const R& right, IntToType<sizeof(No
* e.g. float with long double.
*
* Two objects of types A and B will be fuzzy comparable if either method is defined:
* - bool A::isClose(const B&)
* - bool A::isClose(B)
* - bool B::isClose(const A&)
* - bool B::isClose(A)
* Alternatively, a custom specialization of this function can be defined.
* - bool A::isClose(const B&) const
* - bool A::isClose(B) const
* - bool B::isClose(const A&) const
* - bool B::isClose(A) const
*
* Note that all floating types and their combinations are fuzzy comparable by default:
* - float
* - double
* - long double
* Call areClose(A, B) will be dispatched as follows:
*
* If the arguments aren't fuzzy comparable, this function will resort to the plain comparison operator ==.
* - If A and B are both floating point types (float, double, long double) - possibly different - the call will be
* dispatched to @ref areFloatsClose(). If A and B are different types, value of the larger type will be coerced
* to the smaller type, e.g. areClose(long double, float) --> areClose(float, float).
*
* - If A defines isClose() that accepts B, the call will be dispatched there.
*
* - If B defines isClose() that accepts A, the call will be dispatched there (A/B swapped).
*
* - Last resort is A == B.
*
* Alternatively, a custom behavior can be implemented via template specialization.
*
* See also: @ref UAVCAN_FLOAT_COMPARISON_EPSILON_MULT.
*
@ -143,7 +149,7 @@ inline bool areCloseImplFirst(const L& left, const R& right, IntToType<sizeof(No
* areClose("123", std::string("123")) --> true (using std::string's operator ==)
* areClose(inf, inf) --> true
* areClose(inf, -inf) --> false
* areClose(nan, nan) --> false
* areClose(nan, nan) --> false (any comparison with nan returns false)
* areClose(123, "123") --> compilation error: operator == is not defined
*/
template <typename L, typename R>

View File

@ -84,3 +84,80 @@ TEST(Comparison, BruteforceValidation)
std::cout.precision(default_precision);
}
struct B
{
long double b;
B(long double val = 0.0L) : b(val) { }
};
struct A
{
float a;
explicit A(float val = 0.0F) : a(val) { }
bool isClose(A rhs) const
{
std::cout << "bool A::isClose(A) --> " << rhs.a << std::endl;
return uavcan::areClose(a, rhs.a);
}
bool isClose(const B& rhs) const
{
std::cout << "bool A::isClose(const B&) --> " << rhs.b << std::endl;
return uavcan::areClose(a, rhs.b);
}
};
struct C
{
long long c;
explicit C(long long val = 0.0L) : c(val) { }
bool operator==(B rhs) const
{
std::cout << "bool C::operator==(B) --> " << rhs.b << std::endl;
return c == static_cast<long long>(rhs.b);
}
};
TEST(Comparison, IsCloseMethod)
{
B b;
A a;
C c;
std::cout << 1 << std::endl;
ASSERT_TRUE(uavcan::areClose(a, b)); // Fuzzy
ASSERT_TRUE(uavcan::areClose(a, A())); // Fuzzy
ASSERT_TRUE(uavcan::areClose(b, a)); // Fuzzy, reverse application
ASSERT_TRUE(uavcan::areClose(c, b)); // Exact
std::cout << 2 << std::endl;
a.a = uavcan::NumericTraits<float>::epsilon();
ASSERT_TRUE(uavcan::areClose(a, b));
ASSERT_TRUE(uavcan::areClose(b, a));
ASSERT_TRUE(a.isClose(b));
ASSERT_TRUE(a.isClose(A()));
ASSERT_TRUE(uavcan::areClose(A(), a));
std::cout << 3 << std::endl;
a.a = 1e-5F;
ASSERT_FALSE(uavcan::areClose(a, b));
ASSERT_FALSE(uavcan::areClose(b, a));
ASSERT_FALSE(uavcan::areClose(A(), a));
std::cout << 4 << std::endl;
b.b = 1.1L;
c.c = 1;
ASSERT_TRUE(uavcan::areClose(c, b)); // Round to integer
ASSERT_TRUE(uavcan::areClose(c, 1.0L)); // Implicit cast to B
ASSERT_FALSE(uavcan::areClose(c, 0.0L));
}