diff options
Diffstat (limited to 'host/include')
-rw-r--r-- | host/include/uhd/utils/fp_compare_epsilon.ipp | 68 | ||||
-rw-r--r-- | host/include/uhd/utils/math.hpp | 4 |
2 files changed, 40 insertions, 32 deletions
diff --git a/host/include/uhd/utils/fp_compare_epsilon.ipp b/host/include/uhd/utils/fp_compare_epsilon.ipp index 99e467df4..a00cb0696 100644 --- a/host/include/uhd/utils/fp_compare_epsilon.ipp +++ b/host/include/uhd/utils/fp_compare_epsilon.ipp @@ -9,6 +9,7 @@ #include <cmath> #include <typeinfo> + #pragma once @@ -49,15 +50,32 @@ namespace uhd { namespace math { namespace fp_compare { _epsilon = copy._epsilon; } - template<typename float_t> UHD_INLINE - bool operator==(fp_compare_epsilon<float_t> lhs, fp_compare_epsilon<float_t> rhs) { - - bool lhs_compare = ((std::abs(lhs._value - rhs._value) / std::abs(lhs._value)) + template <typename float_t> + UHD_INLINE bool operator==( + fp_compare_epsilon<float_t> lhs, fp_compare_epsilon<float_t> rhs) + { + // If raw bit values are equal, then they're equal. This also catches + // the case where both are 0.0! + if (lhs._value == rhs._value) { + return true; + } + + // If one of them is within epsilon of zero, but the other is not, then + // they're also not equal. + if ((std::abs(lhs._value) <= lhs._epsilon && std::abs(rhs._value) > rhs._epsilon) + || (std::abs(lhs._value) > lhs._epsilon + && std::abs(rhs._value) <= rhs._epsilon)) { + return false; + } + + // In all other cases, we use the "close enough with tolerance epsilon" + // algorithm as described in math.hpp. + const bool lhs_compare = ((std::abs(lhs._value - rhs._value) / std::abs(lhs._value)) <= lhs._epsilon); - bool rhs_compare = ((std::abs(lhs._value - rhs._value) / std::abs(rhs._value)) + const bool rhs_compare = ((std::abs(lhs._value - rhs._value) / std::abs(rhs._value)) <= rhs._epsilon); - return (lhs_compare && rhs_compare); + return (lhs_compare || rhs_compare); } template<typename float_t> UHD_INLINE @@ -67,7 +85,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator<(fp_compare_epsilon<float_t> lhs, fp_compare_epsilon<float_t> rhs) { - return (lhs._value + lhs._epsilon) < (rhs._value - rhs._epsilon); + return (lhs != rhs) && (lhs._value < rhs._value); } template<typename float_t> UHD_INLINE @@ -77,7 +95,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator>(fp_compare_epsilon<float_t> lhs, fp_compare_epsilon<float_t> rhs) { - return (lhs._value - lhs._epsilon) > (rhs._value + rhs._epsilon); + return (lhs != rhs) && (lhs._value > rhs._value); } template<typename float_t> UHD_INLINE @@ -85,15 +103,10 @@ namespace uhd { namespace math { namespace fp_compare { return !(lhs < rhs); } - template<typename float_t> UHD_INLINE - bool operator==(fp_compare_epsilon<float_t> lhs, double rhs) { - - bool lhs_compare = ((std::abs(lhs._value - rhs) / std::abs(lhs._value)) - <= lhs._epsilon); - bool rhs_compare = ((std::abs(lhs._value - rhs) / std::abs(rhs)) - <= DOUBLE_PRECISION_EPSILON); - - return (lhs_compare && rhs_compare); + template <typename float_t> + UHD_INLINE bool operator==(fp_compare_epsilon<float_t> lhs, double rhs) + { + return lhs == fp_compare_epsilon<float_t>(static_cast<float_t>(rhs)); } template<typename float_t> UHD_INLINE @@ -104,7 +117,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator<(fp_compare_epsilon<float_t> lhs, double rhs) { - return (lhs._value + lhs._epsilon) < (rhs - DOUBLE_PRECISION_EPSILON); + return (lhs != rhs) && (lhs._value < rhs); } template<typename float_t> UHD_INLINE @@ -115,7 +128,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator>(fp_compare_epsilon<float_t> lhs, double rhs) { - return (lhs._value - lhs._epsilon) > (rhs + DOUBLE_PRECISION_EPSILON); + return (lhs != rhs) && (lhs._value > rhs); } template<typename float_t> UHD_INLINE @@ -123,15 +136,10 @@ namespace uhd { namespace math { namespace fp_compare { return !(lhs < rhs); } - template<typename float_t> UHD_INLINE - bool operator==(double lhs, fp_compare_epsilon<float_t> rhs) { - - bool lhs_compare = ((std::abs(lhs - rhs._value) / std::abs(lhs)) - <= DOUBLE_PRECISION_EPSILON); - bool rhs_compare = ((std::abs(lhs - rhs._value) / std::abs(rhs._value)) - <= rhs._epsilon); - - return (lhs_compare && rhs_compare); + template <typename float_t> + UHD_INLINE bool operator==(double lhs, fp_compare_epsilon<float_t> rhs) + { + return fp_compare_epsilon<float_t>(static_cast<float_t>(lhs)) == rhs; } template<typename float_t> UHD_INLINE @@ -142,7 +150,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator<(double lhs, fp_compare_epsilon<float_t> rhs) { - return (lhs + DOUBLE_PRECISION_EPSILON) < (rhs._value - rhs._epsilon); + return (lhs != rhs) && (lhs < rhs._value); } template<typename float_t> UHD_INLINE @@ -153,7 +161,7 @@ namespace uhd { namespace math { namespace fp_compare { template<typename float_t> UHD_INLINE bool operator>(double lhs, fp_compare_epsilon<float_t> rhs) { - return (lhs - DOUBLE_PRECISION_EPSILON) > (rhs._value + rhs._epsilon); + return (lhs != rhs) && (lhs > rhs._value); } template<typename float_t> UHD_INLINE diff --git a/host/include/uhd/utils/math.hpp b/host/include/uhd/utils/math.hpp index 6c8fceae9..6ee46e98a 100644 --- a/host/include/uhd/utils/math.hpp +++ b/host/include/uhd/utils/math.hpp @@ -85,10 +85,10 @@ public: * There are obviously a lot of strategies for defining floating point * equality, and in the end it all comes down to the domain at hand. UHD's * floating-point-with-epsilon comparison algorithm is based on the method - * presented in Knuth's "The Art of Computer Science" called "very close + * presented in Knuth's "The Art of Computer Science" called "close enough * with tolerance epsilon". * - * [(|u - v| / |u|) <= e] && [(|u - v| / |v|) <= e] + * [(|u - v| / |u|) <= e] || [(|u - v| / |v|) <= e] * * UHD's modification to this algorithm is using the denominator's epsilon * value (since each float_t object has its own epsilon) for each |