/* * Copyright (C) 2014 Pavel Kirienko */ #pragma once #include #include namespace uavcan { /** * Exact comparison of two floats that suppresses the compiler warnings. */ template UAVCAN_EXPORT inline bool areFloatsExactlyEqual(const T& left, const T& right) { return (left <= right) && (left >= 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/ */ template UAVCAN_EXPORT inline bool areFloatsClose(T a, T b, const T absolute_epsilon, const T relative_epsilon) { // NAN if (isNaN(a) || isNaN(b)) { return false; } // Infinity if (isInfinity(a) || isInfinity(b)) { return areFloatsExactlyEqual(a, b); } // Close numbers near zero const T diff = std::fabs(a - b); if (diff <= absolute_epsilon) { return true; } // General case a = std::fabs(a); b = std::fabs(b); const T largest = (b > a) ? b : a; return (diff <= largest * relative_epsilon); } /** * Generic comparison function. * This function properly handles floating point comparison, including mixed floating point type comparison, * e.g. float with long double. */ template UAVCAN_EXPORT inline bool areClose(const L& left, const R& right) { return left == right; } /* * Float comparison specializations */ template <> UAVCAN_EXPORT inline bool areClose(const float& left, const float& right) { return areFloatsClose(left, right, NumericTraits::epsilon(), NumericTraits::epsilon() * FloatComparisonEpsilonMult); } template <> UAVCAN_EXPORT inline bool areClose(const double& left, const double& right) { return areFloatsClose(left, right, NumericTraits::epsilon(), NumericTraits::epsilon() * FloatComparisonEpsilonMult); } template <> UAVCAN_EXPORT inline bool areClose(const long double& left, const long double& right) { return areFloatsClose(left, right, NumericTraits::epsilon(), NumericTraits::epsilon() * FloatComparisonEpsilonMult); } /* * Mixed floating type comparison - coercing larger type to smaller type */ template <> UAVCAN_EXPORT inline bool areClose(const float& left, const double& right) { return areClose(left, static_cast(right)); } template <> UAVCAN_EXPORT inline bool areClose(const double& left, const float& right) { return areClose(static_cast(left), right); } template <> UAVCAN_EXPORT inline bool areClose(const float& left, const long double& right) { return areClose(left, static_cast(right)); } template <> UAVCAN_EXPORT inline bool areClose(const long double& left, const float& right) { return areClose(static_cast(left), right); } template <> UAVCAN_EXPORT inline bool areClose(const double& left, const long double& right) { return areClose(left, static_cast(right)); } template <> UAVCAN_EXPORT inline bool areClose(const long double& left, const double& right) { return areClose(static_cast(left), right); } /** * Comparison against zero. * Helps to compare a floating point number against zero if the exact type is unknown. * For non-floating point types performs exact comparison against integer zero. */ template UAVCAN_EXPORT inline bool isCloseToZero(const T& x) { return x == 0; } template <> UAVCAN_EXPORT inline bool isCloseToZero(const float& x) { return areClose(x, static_cast(0.0F)); } template <> UAVCAN_EXPORT inline bool isCloseToZero(const double& x) { return areClose(x, static_cast(0.0)); } template <> UAVCAN_EXPORT inline bool isCloseToZero(const long double& x) { return areClose(x, static_cast(0.0L)); } }