mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
areClose(), isClose()
This commit is contained in:
parent
f255a725c1
commit
9d806c2be6
@ -107,13 +107,15 @@ struct UAVCAN_EXPORT ${t.cpp_type_name}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operators are based on @ref uavcan::areClose(),
|
||||
* which allows to safely compare floating point values.
|
||||
*/
|
||||
bool operator==(ParameterType rhs) const;
|
||||
bool operator!=(ParameterType rhs) const { return !operator==(rhs); }
|
||||
|
||||
/**
|
||||
* This comparison is based on @ref uavcan::areClose(), which ensures proper comparison of
|
||||
* floating point fields at any depth.
|
||||
*/
|
||||
bool isClose(ParameterType rhs) const;
|
||||
|
||||
static int encode(ParameterType self, ::uavcan::ScalarCodec& codec,
|
||||
::uavcan::TailArrayOptimizationMode tao_mode = ::uavcan::TailArrayOptEnabled);
|
||||
|
||||
@ -182,6 +184,20 @@ UAVCAN_PACKED_END
|
||||
|
||||
template <int _tmpl>
|
||||
bool ${scope_prefix}<_tmpl>::operator==(ParameterType rhs) const
|
||||
{
|
||||
% if fields:
|
||||
return
|
||||
% for idx,a in enumerate(fields):
|
||||
${a.name} == rhs.${a.name}${' &&' if (idx + 1) < len(fields) else ';'}
|
||||
% endfor
|
||||
% else:
|
||||
(void)rhs;
|
||||
return true;
|
||||
% endif
|
||||
}
|
||||
|
||||
template <int _tmpl>
|
||||
bool ${scope_prefix}<_tmpl>::isClose(ParameterType rhs) const
|
||||
{
|
||||
% if fields:
|
||||
return
|
||||
|
||||
@ -577,11 +577,36 @@ public:
|
||||
|
||||
/**
|
||||
* This operator accepts any container with size() and [].
|
||||
* Members are compared via @ref areClose().
|
||||
* Members must be comparable via operator ==.
|
||||
*/
|
||||
template <typename R>
|
||||
typename EnableIf<sizeof(((const R*)(0U))->size()) && sizeof((*((const R*)(0U)))[0]), bool>::Type
|
||||
operator==(const R& rhs) const
|
||||
{
|
||||
if (size() != rhs.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (SizeType i = 0; i < size(); i++) // Bitset does not have iterators
|
||||
{
|
||||
if (!(Base::at(i) == rhs[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method compares two arrays using @ref areClose(), which ensures proper comparison of
|
||||
* floating point values, or DSDL data structures which contain floating point fields at any depth.
|
||||
* Please refer to the documentation of @ref areClose() to learn more about how it works and how to
|
||||
* define custom fuzzy comparison behavior.
|
||||
* Any container with size() and [] is acceptable.
|
||||
*/
|
||||
template <typename R>
|
||||
typename EnableIf<sizeof(((const R*)(0U))->size()) && sizeof((*((const R*)(0U)))[0]), bool>::Type
|
||||
isClose(const R& rhs) const
|
||||
{
|
||||
if (size() != rhs.size())
|
||||
{
|
||||
|
||||
@ -23,6 +23,7 @@ inline bool areFloatsExactlyEqual(const T& left, const T& right)
|
||||
* This function performs fuzzy comparison of two floating point numbers.
|
||||
* Type of T can be either float, double or long double.
|
||||
* For details refer to http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
|
||||
* See also: @ref UAVCAN_FLOAT_COMPARISON_EPSILON_MULT.
|
||||
*/
|
||||
template <typename T>
|
||||
UAVCAN_EXPORT
|
||||
@ -55,15 +56,102 @@ inline bool areFloatsClose(T a, T b, const T absolute_epsilon, const T relative_
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic comparison function.
|
||||
* This namespace contains implementation details for areClose().
|
||||
* Don't try this at home.
|
||||
*/
|
||||
namespace are_close_impl_
|
||||
{
|
||||
|
||||
struct Applicable { char foo[1]; };
|
||||
struct NotApplicable { long long foo[16]; };
|
||||
|
||||
template <typename This, typename Rhs>
|
||||
struct HasIsCloseMethod
|
||||
{
|
||||
template <typename U, typename R, bool (U::*)(const R&) const> struct ConstRef { };
|
||||
template <typename U, typename R, bool (U::*)(R) const> struct ByValue { };
|
||||
|
||||
template <typename U, typename R> static Applicable test(ConstRef<U, R, &U::isClose>*);
|
||||
template <typename U, typename R> static Applicable test(ByValue<U, R, &U::isClose>*);
|
||||
|
||||
template <typename U, typename R> static NotApplicable test(...);
|
||||
|
||||
enum { Result = sizeof(test<This, Rhs>(NULL)) };
|
||||
};
|
||||
|
||||
/// First stage: bool L::isClose(R)
|
||||
template <typename L, typename R>
|
||||
UAVCAN_EXPORT
|
||||
inline bool areCloseImplFirst(const L& left, const R& right, IntToType<sizeof(Applicable)>)
|
||||
{
|
||||
return left.isClose(right);
|
||||
}
|
||||
|
||||
/// Second stage: bool R::isClose(L)
|
||||
template <typename L, typename R>
|
||||
UAVCAN_EXPORT
|
||||
inline bool areCloseImplSecond(const L& left, const R& right, IntToType<sizeof(Applicable)>)
|
||||
{
|
||||
return right.isClose(left);
|
||||
}
|
||||
|
||||
/// Second stage: L == R
|
||||
template <typename L, typename R>
|
||||
UAVCAN_EXPORT
|
||||
inline bool areCloseImplSecond(const L& left, const R& right, IntToType<sizeof(NotApplicable)>)
|
||||
{
|
||||
return left == right;
|
||||
}
|
||||
|
||||
/// First stage: select either L == R or bool R::isClose(L)
|
||||
template <typename L, typename R>
|
||||
UAVCAN_EXPORT
|
||||
inline bool areCloseImplFirst(const L& left, const R& right, IntToType<sizeof(NotApplicable)>)
|
||||
{
|
||||
return are_close_impl_::areCloseImplSecond(left, right,
|
||||
IntToType<are_close_impl_::HasIsCloseMethod<R, L>::Result>());
|
||||
}
|
||||
|
||||
} // namespace are_close_impl_
|
||||
|
||||
/**
|
||||
* Generic fuzzy comparison function.
|
||||
*
|
||||
* This function properly handles floating point comparison, including mixed floating point type comparison,
|
||||
* 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.
|
||||
*
|
||||
* Note that all floating types and their combinations are fuzzy comparable by default:
|
||||
* - float
|
||||
* - double
|
||||
* - long double
|
||||
*
|
||||
* If the arguments aren't fuzzy comparable, this function will resort to the plain comparison operator ==.
|
||||
*
|
||||
* See also: @ref UAVCAN_FLOAT_COMPARISON_EPSILON_MULT.
|
||||
*
|
||||
* Examples:
|
||||
* areClose(1.0, 1.0F) --> true
|
||||
* areClose(1.0, 1.0F + std::numeric_limits<float>::epsilon()) --> true
|
||||
* areClose(1.0, 1.1) --> false
|
||||
* areClose("123", std::string("123")) --> true (using std::string's operator ==)
|
||||
* areClose(inf, inf) --> true
|
||||
* areClose(inf, -inf) --> false
|
||||
* areClose(nan, nan) --> false
|
||||
* areClose(123, "123") --> compilation error: operator == is not defined
|
||||
*/
|
||||
template <typename L, typename R>
|
||||
UAVCAN_EXPORT
|
||||
inline bool areClose(const L& left, const R& right)
|
||||
{
|
||||
return left == right;
|
||||
return are_close_impl_::areCloseImplFirst(left, right,
|
||||
IntToType<are_close_impl_::HasIsCloseMethod<L, R>::Result>());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#if __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/transport/transfer_buffer.hpp>
|
||||
#include <limits>
|
||||
@ -85,10 +89,12 @@ TEST(Dsdl, CloseComparison)
|
||||
ASSERT_TRUE(first == second);
|
||||
|
||||
first.vector[1].vector[1] = std::numeric_limits<double>::epsilon();
|
||||
ASSERT_TRUE(first == second); // Still equals
|
||||
ASSERT_TRUE(first.isClose(second)); // Still close
|
||||
ASSERT_FALSE(first == second); // But not exactly
|
||||
|
||||
first.vector[1].vector[1] = std::numeric_limits<float>::epsilon();
|
||||
ASSERT_FALSE(first == second); // Nope
|
||||
ASSERT_FALSE(first.isClose(second)); // Nope
|
||||
ASSERT_FALSE(first == second); // Ditto
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#if __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/marshal/types.hpp>
|
||||
#include <uavcan/transport/transfer_buffer.hpp>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user