From 8b73a68de8a71d9964fdc375a65002f1addf9111 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Fri, 29 Aug 2014 01:25:55 +0400 Subject: [PATCH] areClose() tests and docs --- libuavcan/include/uavcan/util/comparison.hpp | 28 ++++--- libuavcan/test/util/comparison.cpp | 77 ++++++++++++++++++++ 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/libuavcan/include/uavcan/util/comparison.hpp b/libuavcan/include/uavcan/util/comparison.hpp index b63eb49e5c..c66db5b54a 100644 --- a/libuavcan/include/uavcan/util/comparison.hpp +++ b/libuavcan/include/uavcan/util/comparison.hpp @@ -121,18 +121,24 @@ inline bool areCloseImplFirst(const L& left, const R& right, IntToType 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 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 diff --git a/libuavcan/test/util/comparison.cpp b/libuavcan/test/util/comparison.cpp index f261ddf68b..10ef7042d6 100644 --- a/libuavcan/test/util/comparison.cpp +++ b/libuavcan/test/util/comparison.cpp @@ -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(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::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)); +}