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
+17 -11
View File
@@ -121,18 +121,24 @@ inline bool areCloseImplFirst(const L& left, const R& right, IntToType<sizeof(No
* e.g. float with long double. * e.g. float with long double.
* *
* Two objects of types A and B will be fuzzy comparable if either method is defined: * Two objects of types A and B will be fuzzy comparable if either method is defined:
* - bool A::isClose(const B&) * - bool A::isClose(const B&) const
* - bool A::isClose(B) * - bool A::isClose(B) const
* - bool B::isClose(const A&) * - bool B::isClose(const A&) const
* - bool B::isClose(A) * - bool B::isClose(A) const
* Alternatively, a custom specialization of this function can be defined.
* *
* Note that all floating types and their combinations are fuzzy comparable by default: * Call areClose(A, B) will be dispatched as follows:
* - float
* - double
* - long double
* *
* 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. * 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("123", std::string("123")) --> true (using std::string's operator ==)
* areClose(inf, inf) --> true * areClose(inf, inf) --> true
* areClose(inf, -inf) --> false * 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 * areClose(123, "123") --> compilation error: operator == is not defined
*/ */
template <typename L, typename R> template <typename L, typename R>
+77
View File
@@ -84,3 +84,80 @@ TEST(Comparison, BruteforceValidation)
std::cout.precision(default_precision); 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));
}