$search
00001 00011 /***************************************************************************** 00012 ** Ifdefs 00013 *****************************************************************************/ 00014 00015 #ifndef ECL_MATH_FUZZY_HPP_ 00016 #define ECL_MATH_FUZZY_HPP_ 00017 00018 /***************************************************************************** 00019 ** Includes 00020 *****************************************************************************/ 00021 00022 //#include "num_traits.hpp" 00023 #include <cmath> // floating point std::abs 00024 #include <cstdlib> // integral std::abs 00025 #include <algorithm> // std::min, std::max 00026 #include <ecl/type_traits/numeric_limits.hpp> 00027 00028 /***************************************************************************** 00029 ** Namespaces 00030 *****************************************************************************/ 00031 00032 namespace ecl { 00036 namespace implementations { 00037 00038 /**************************************************************************** 00039 * Implementation of fuzzy comparisons * 00040 ****************************************************************************/ 00041 00047 template<typename Scalar, 00048 bool IsInteger> 00049 struct scalar_fuzzy_default_impl {}; 00050 00056 template<typename Scalar> 00057 struct scalar_fuzzy_default_impl<Scalar, false> 00058 { 00059 typedef typename ecl::numeric_limits<Scalar>::Precision Precision; 00060 00061 template<typename OtherScalar> 00062 static inline bool isApprox(const Scalar& x, const OtherScalar& y, const Precision& prec) { 00063 // casting just in case y is an integer type. 00064 return std::abs(x - static_cast<Scalar>(y)) <= std::min( std::abs(x), std::abs(static_cast<Scalar>(y))) * prec; 00065 } 00066 00067 template<typename OtherScalar> 00068 static inline bool isApproxOrLessThan(const Scalar& x, const OtherScalar& y, const Precision& prec) { 00069 return x <= y || isApprox(x, y, prec); 00070 } 00071 }; 00072 00078 template<typename Scalar> 00079 struct scalar_fuzzy_default_impl<Scalar, true> { 00080 00081 typedef typename ecl::numeric_limits<Scalar>::Precision Precision; 00082 00083 template<typename OtherScalar> 00084 static inline bool isApprox(const Scalar& x, const OtherScalar& y, const Precision& prec) { 00085 // this will trigger if default argument is used (dummy precision for integers == 0) 00086 if ( ecl::numeric_limits<OtherScalar>::is_integer ) { 00087 return x == y; 00088 } else { 00089 // only get here if its not complex, so OtherScalar has to be a floating type 00090 typename ecl::numeric_limits<OtherScalar>::Precision precision; 00091 if ( prec == 0.0 ) { 00092 precision = ecl::numeric_limits<OtherScalar>::dummy_precision; 00093 } else { 00094 precision = static_cast<OtherScalar>(prec); 00095 } 00096 return std::abs(static_cast<OtherScalar>(x) - y) <= std::min( std::abs(static_cast<OtherScalar>(x)), std::abs(y)) * precision; 00097 } 00098 } 00099 template<typename OtherScalar> 00100 static inline bool isApproxOrLessThan(const Scalar& x, const OtherScalar& y, const Precision&) { 00101 return x <= y; 00102 } 00103 }; 00104 00106 // * @brief Fuzzy math implementation for complex numbers. 00107 // * 00108 // * Specialisation of fuzzy math functions for complex numbers. 00109 // * 00110 // * @tparam Scalar : autoselected by numeric traits as always being complex. 00111 // */ 00112 //template<typename Scalar> 00113 //struct scalar_fuzzy_default_impl<Scalar, true, false> { 00114 // typedef typename ecl::NumTraits<Scalar>::Precision Precision; 00115 // 00116 // static inline bool isApprox(const Scalar& x, const Scalar& y, const Precision& prec) { 00117 // return ei_abs2(x - y) <= std::min(ei_abs2(x), ei_abs2(y)) * prec * prec; 00118 // } 00119 //}; 00120 00128 template<typename Scalar> 00129 struct scalar_fuzzy_impl : implementations::scalar_fuzzy_default_impl<Scalar, numeric_limits<Scalar>::is_integer> {}; 00130 00131 } // implementations 00132 00136 /***************************************************************************** 00137 ** Direct Interfaces 00138 *****************************************************************************/ 00139 00153 template<typename Scalar, typename OtherScalar> 00154 inline bool isApprox(const Scalar& x, const OtherScalar& y, typename numeric_limits<Scalar>::Precision precision = numeric_limits<Scalar>::dummy_precision) { 00155 return implementations::scalar_fuzzy_impl<Scalar>::isApprox(x, y, precision); 00156 } 00157 00171 template<typename Scalar, typename OtherScalar> 00172 inline bool isApproxOrLessThan(const Scalar& x, const OtherScalar& y, typename numeric_limits<Scalar>::Precision precision = numeric_limits<Scalar>::dummy_precision) { 00173 return implementations::scalar_fuzzy_impl<Scalar>::isApproxOrLessThan(x, y, precision); 00174 } 00175 00176 00177 00178 } // namespace ecl 00179 00180 #endif /* ECL_MATH_FUZZY_HPP_ */