//@doc///////////////////////////////////////////////////////////////////////////////////////// // // SIERRA S.R.L. - Tecnología y Servicio - Departamento de Software. // //============================================================================================= // Generic Math Library. Fernando Cacciola. // // 21/09/1999 FLC Initial build. // 28/03/2001 FLC compare_n() added (-1,0,+1) // #ifndef __RTL_GENERIC_MATH_H_ #define __RTL_GENERIC_MATH_H_ #include #include #include using std::numeric_limits ; #include "cvt_n.h" namespace gmath { ////////////////////////////////////////////////////////////////////////////////////////// // Parametrized Constants. // // The following parametrized constants are needed in order to avoid loss of precision // in user defined numeric types. // Consider this example: // // A generic algorithm needs to compare a value v to the number pi. // If the code were: if ( v == T(M_PI) ) (Or equal_e(v,T(M_PI)) for that matter) // the constant expression T(M_PI) may loose precision. // Instead, using : if ( v == gmath::cPi() ) will keep as much precision as posible. // // These constants should be specialized for user defined types when more accurate // values are available. Otherwise, double values will be used. // // NOTE: Don't use this for constants that would not loose precision. // Constant expressions such as T(0),T(.5) should be ok. // template inline T cHalfPi() { return static_cast(M_PI_2) ; } template inline T cPi() { return static_cast(M_PI) ; } template inline T cThreeHalfPi() { return static_cast(3.0 * M_PI_2) ; } template inline T cTwoPi() { return static_cast(2.0 * M_PI) ; } template inline T cMinusHalfPi() { return static_cast(- M_PI_2) ; } template inline T cMinusPi() { return static_cast(- M_PI) ; } template inline T cMinusThreeHalfPi() { return static_cast(- 3.0 * M_PI_2) ; } template inline T cMinusTwoPi() { return static_cast(- 2.0 * M_PI) ; } template inline T cRadian() { return static_cast(360.0 / ( 2.0 * M_PI )) ; } template inline T cEpsilon() { return numeric_limits::epsilon() ; } template inline T cInfinite() { return numeric_limits::max() ; } // ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // The following is a library of math functions generalized for arbitrary numeric types. // It contains: // Most standard math functions (abs,cos,sqrt,etc...). // Misc functions. // An epsilon-based comparator, and standalong related functions // zero_e(),equal_e(),lower_e(),etc... // // All this functions are implemented using the standard math functions for type 'double' // The convertion template cvt_n<> is used to convert from/to double. // // Type T MUST supply the arithmetic operators + - * / and the relational operators // ==,!=,< // // Each one of these functions can be specialized for a given type, but it is not // necesary if convertion to/from double is provided via cvt_n<> // // The basic functions below work internally with type double. // For a given arbitrary type, at least cvt_n(T) and cvt_n(double) should be // defined. // This will allow the basic functions to be properly instantiated and used. //-------------------------------------------------------------------------------------- // // Standard C++ Math functions. // // NOTE: abs() and mod() signatures are used instead of fabs() and fmod(). // template inline T abs ( T const& v ) { return cvt_n(std::fabs(cvt_n(v))) ; } template inline T cos ( T const& v ) { return cvt_n(std::cos(cvt_n(v))) ; } template inline T sin ( T const& v ) { return cvt_n(std::sin(cvt_n(v))) ; } template inline T tan ( T const& v ) { return cvt_n(std::tan(cvt_n(v))) ; } template inline T acos ( T const& v ) { return cvt_n(std::acos(cvt_n(v))) ; } template inline T asin ( T const& v ) { return cvt_n(std::asin(cvt_n(v))) ; } template inline T atan ( T const& v ) { return cvt_n(std::atan(cvt_n(v))) ; } template inline T cosh ( T const& v ) { return cvt_n(std::cosh(cvt_n(v))) ; } template inline T sinh ( T const& v ) { return cvt_n(std::sinh(cvt_n(v))) ; } template inline T atan2 ( T const& y , T const& x ) { return cvt_n(std::atan2(cvt_n(y),cvt_n(x))) ; } template inline T floor ( T const& v ) { return cvt_n(std::floor(cvt_n(v))) ; } template inline T ceil ( T const& v ) { return cvt_n(std::ceil(cvt_n(v))) ; } template inline T log ( T const& v ) { return cvt_n(std::log(cvt_n(v))) ; } template inline T log10 ( T const& v ) { return cvt_n(std::log10(cvt_n(v))) ; } template inline T exp ( T const& v ) { return cvt_n(std::exp(cvt_n(v))) ; } template inline T modf ( T const& v , T& n ) { double _n ; T r = cvt_n(std::modf(cvt_n(v),&_n)) ; n = cvt_n(_n); return r ; } template inline T hypot ( T const& dx , T const& dy ) { return cvt_n(std::hypot(cvt_n(dx),cvt_n(dy))) ; } template inline T mod ( T const& u , T const& v ) { return cvt_n(std::fmod(cvt_n(u),cvt_n(v))) ; } template inline T sqrt ( T const& v ) { return cvt_n(std::sqrt(cvt_n(v))) ; } //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // // Additional NON-STANDARD functions // // These functions are implemented using the above. // Some user defined types might have their special versions. // v * v template inline T pow2 ( T const& v ) { return v * v ; } // u ^ v template inline T pow ( T const& u , T const& v ) { return u ^ v ; } template inline T sec ( T const& v ) { return inverse(cos (v)); } template inline T cosec ( T const& v ) { return inverse(sin (v)); } template inline T cotan ( T const& v ) { return inverse(tan (v)); } template inline T sech ( T const& v ) { return inverse(cosh(v)); } template inline T cosech( T const& v ) { return inverse(sinh(v)); } // -v template inline T oposite ( T const& v ) { return - v ; } // 1/v template inline T inverse ( T const& v ) { return T(1) / v ; } // rounds towards closer. template inline T round ( T const& v ) { return floor( v + T(0.5) ) ; } // |a-b|, implemented with a comparison. template inline T absdiff ( T const& a , T const& b ) { return a < b ? b - a : a - b ; } // average of a,b template inline T mid ( T const& a , T const& b ) { return ( a + b ) / T(2) ; } //-------------------------------------------------------------------------------------- // // template struct numeric_comparator { typedef T N ; struct epsilon { static T value() { return cEpsilon() ; } } ; static bool zero ( N const& aN ) { return abs(aN) <= epsilon::value() ; } static bool zero ( N const& aN , N const& e ) { return abs(aN) <= e ; } static bool equal ( N const& aA, N const& aB ) { return abs(aA - aB) <= epsilon::value() ; } static bool equal ( N const& aA, N const& aB , N const& e ) { return abs(aA - aB) <= e ; } // -1,0,1 for < == > static int compare ( T const& aA, T const& aB ) { return equal(aA,aB,epsilon::value()) ? 0 : ( aA < aB ? -1 : +1 ) ; } static int compare ( T const& aA, T const& aB , N const& e ) { return equal(aA,aB,e) ? 0 : ( aA < aB ? -1 : +1 ) ; } } ; template<> struct numeric_comparator { static bool zero ( int aN ) { return aN == 0 ; } static bool zero ( int aN, int e ) { return aN == e ; } static bool equal ( int aA, int aB ) { return aA == aB ; } static bool equal ( int aA, int aB, int e ) { return abs(aA-aB) <= e ; } // -1,0,1 for < == > static int compare ( int aA, int aB ) { return aA == aB ? 0 : ( aA < aB ? -1 : +1 ) ; } static int compare ( int aA, int aB, int e ) { return equal(aA,aB,e) ? 0 : ( aA < aB ? -1 : +1 ) ; } } ; template inline int get_sign ( T const& v ) { if ( v == T(0) ) return 0 ; else return ( v > T(0) ? 1 : -1 ) ; } // Rerturns +1 if v==+0.0, -1 if v==-0.0, 0 otherwise. // If T is not 'double', the result depends on to convertion to 'double' template inline int get_zero_sign ( T const& v ) { int cls = _fpclass( cvt_n(v) ); return cls == _FPCLASS_PZ ? +1 : ( cls==_FPCLASS_NZ ? -1 : 0 ) ; } // true if v is STRICTLY POSITIVE, that is, >0 template inline bool pos ( T const& v ) { return get_sign(v) == 1 ; } // true if v is STRICTLY NEGATIVE, that is, <0 template inline bool neg ( T const& v ) { return get_sign(v) == -1 ; } // true if v is an even number, that is, v%2==0 template inline bool even ( T const& v ) { return mod ( v , T(2) ) == T(0) ; } // true if v is an odd number, that is, v%2!=0 template inline bool odd ( T const& v ) { return ! even ( v ) ; } // true if v is not a number. // NOTE: Compiler specific implementation. template inline bool is_nan ( T const& n ) { return _isnan(n) ; } // true if v is a value representing infinite. // NOTE: Compiler specific implementation. template inline bool is_inf ( T const& n ) { return numeric_comparator::equal(n,cInfinite()) || ! _finite(n); } //---------------------------------------------------------------------------------------- // ordering relations based on operator <. // The following relational functions are implemented using only T's operator <. //---------------------------------------------------------------------------------------- template inline int compare_n ( T const& u , T const& v ) { return u inline bool less_n ( T const& u , T const& v ) { return u inline bool greater_n ( T const& u , T const& v ) { return v inline bool less_equal_n ( T const& u , T const& v ) { return !(v inline bool greater_equal_n ( T const& u , T const& v ) { return !(u inline bool equal_to_n ( T const& u , T const& v ) { return !(u inline T const& min_n ( T const& a , T const& b ) { return less_n(a,b) ? a : b ; } template inline T const& max_n ( T const& a , T const& b ) { return less_n(a,b) ? b : a ; } //-------------------------------------------------------------------------------------- // range checking based on operator <. //-------------------------------------------------------------------------------------- // true if v is in [l,h] template inline bool inRange ( T const& l , T const& v , T const& h ) { return less_equal_n(l,v) && less_equal_n(v,h) ; } // true if v is in (l,h) template inline bool inOpenRange ( T const& l , T const& v , T const& h ) { return less_n(l,v) && less_n(v,h) ; } // true if v is in (l,h] template inline bool inOpenCloseRange ( T const& l , T const& v , T const& h ) { return less_n(l,v) && less_equal_n(v,h) ; } // true if v is in [l,h) template inline bool inCloseOpenRange ( T const& l , T const& v , T const& h ) { return less_equal_n (l,v) && less_n(v,h) ; } //-------------------------------------------------------------------------------------- // Epsilon-based comparisons. // // All these functions recieves an 'epsilon' parameter. // Numbers are considered equal if they are separated less than or equal to epsilon. // // Notation: a=~=n means: a is almost equal to b, that is, |a-b|<=epsilon // // NOTICE that the epsilon parameter is INCLUSIVE (allowing e=0) // // FINAL NOTE: The epsilon parameter IS NOT SCALED to match the arguments relative // accuaracy. This is because scaling schemes are domain specific, and this is a low-level // general purpose numeric library. // You should use your own scaling wrapper, typically: // // bool my_equal(double u, double v ) // { return gmath::equal_e(u,v, MY_EPSILON * max(abs(u),abs(v))) ;} // //-------------------------------------------------------------------------------------- // 0 if u=~=v // -1 if uv template inline int compare_e ( T const& u, T const& v ) { return numeric_comparator::compare(u,v) ; } template inline int compare_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::compare(u,v,e) ; } // true if v=~=0 template inline bool zero_e ( T const& v ) { return numeric_comparator::zero(v) ; } template inline bool zero_e ( T const& v, T const& e ) { return numeric_comparator::zero(v,e) ; } // true if u=~=v template inline bool equal_e ( T const& u, T const& v ) { return numeric_comparator::equal(u,v) ; } template inline bool equal_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::equal(u,v,e) ; } // true if u inline bool lower_equal_e ( T const& u, T const& v ) { return numeric_comparator::compare(u,v) <= 0 ; } template inline bool lower_equal_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::compare(u,v,e) <= 0 ; } // true if u>v || u=~=v // NOTE: This is not the same as u>v. template inline bool higher_equal_e ( T const& u, T const& v ) { return numeric_comparator::compare(u,v) >= 0 ; } template inline bool higher_equal_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::compare(u,v,e) >= 0 ; } // true if u inline bool lower_e ( T const& u, T const& v ) { return numeric_comparator::compare(u,v) < 0 ; } template inline bool lower_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::compare(u,v,e) < 0 ; } // true if u>v && !(u=~=v) // NOTE: This is not the same as u>v. template inline bool higher_e ( T const& u, T const& v ) { return numeric_comparator::compare(u,v) > 0 ; } template inline bool higher_e ( T const& u, T const& v, T const& e ) { return numeric_comparator::compare(u,v,e) > 0 ; } //-------------------------------------------------------------------------------------- // Epsilon-based range checking. //-------------------------------------------------------------------------------------- // true if v is in [l,h] template inline bool inRange_e ( T const& l, T const& v, T const& h ) { return lower_equal_e(l,v) && lower_equal_e(v,h) ; } template inline bool inRange_e ( T const& l, T const& v, T const& h, T const& e ) { return lower_equal_e(l,v,e) && lower_equal_e(v,h,e) ; } // true if v is in (l,h) template inline bool inOpenRange_e ( T const& l, T const& v, T const& h ) { return lower_e(l,v) && lower_e(v,h) ; } template inline bool inOpenRange_e ( T const& l, T const& v, T const& h, T const& e ) { return lower_e(l,v,e) && lower_e(v,h,e) ; } // true if v is in (l,h] template inline bool inOpenCloseRange_e ( T const& l, T const& v, T const& h ) { return lower_e(l,v) && lower_equal_e(v,h) ; } template inline bool inOpenCloseRange_e ( T const& l, T const& v, T const& h, T const& e ) { return lower_e(l,v,e) && lower_equal_e(v,h,e) ; } // true if v is in [l,h) template inline bool inCloseOpenRange_e ( T const& l, T const& v, T const& h ) { return lower_equal_e (l,v) && lower_e(v,h) ; } template inline bool inCloseOpenRange_e ( T const& l, T const& v, T const& h, T const& e ) { return lower_equal_e (l,v,e) && lower_e(v,h,e) ; } // ////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------- template<> inline double cEpsilon() { return 1e-5 ; } //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- // out-of-line specialization of pow() for built-in floating point types. // template<> inline float pow ( float const& u , float const& v) { return (float) std::pow(u,v) ; } template<> inline double pow ( double const& u , double const& v) { return std::pow(u,v) ; } template<> inline long double pow ( long double const& u , long double const& v) { return std::powl(u,v) ; } //---------------------------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////////////////////// // // long double specializations. // Defined since the Standard math libraries provides functions specific to long double. // template<> inline long double abs ( const long double& v ) { return std::fabsl ( v ) ; } template<> inline long double cos ( const long double& v ) { return std::cosl ( v ) ; } template<> inline long double sin ( const long double& v ) { return std::sinl ( v ) ; } template<> inline long double tan ( const long double& v ) { return std::tanl ( v ) ; } template<> inline long double acos ( const long double& v ) { return std::acosl ( v ) ; } template<> inline long double asin ( const long double& v ) { return std::asinl ( v ) ; } template<> inline long double atan ( const long double& v ) { return std::atanl ( v ) ; } template<> inline long double atan2 ( const long double& y , const long double& x ) { return std::atan2l ( y , x ) ; } template<> inline long double floor ( const long double& v ) { return std::floorl( v ) ; } template<> inline long double ceil ( const long double& v ) { return std::ceill ( v ) ; } template<> inline long double modf ( const long double& v , long double& n ) { return std::modfl ( v , & (n) ) ; } template<> inline long double hypot ( const long double& dx , const long double& dy ) { return std::hypotl ( dx , dy ) ; } template<> inline long double mod ( const long double& u , const long double& v ) { return std::fmodl ( u , v ) ; } template<> inline long double cosh ( const long double& v ) { return std::coshl ( v ) ; } template<> inline long double sinh ( const long double& v ) { return std::sinhl ( v ) ; } template<> inline long double sqrt ( const long double& v ) { return std::sqrtl ( v ) ; } template<> inline long double cEpsilon() { return 1e-7 ; } // ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // // integer specializations. // template<> inline short abs ( short const& v ) { return (short)std::abs((int)v) ; } template<> inline short floor( short const& v ) { return v ; } template<> inline short ceil ( short const& v ) { return v ; } template<> inline short modf ( short const& v , short& n ) { n = 0 ; return v ; } template<> inline short round( short const& v ) { return v ; } template<> inline short mod ( short const& a , short const& b ) { return (short)((int)a % (int)b) ; } template<> inline unsigned short abs ( unsigned short const& v ) { return (unsigned short)std::abs((unsigned int)v ) ; } template<> inline unsigned short floor( unsigned short const& v ) { return v ; } template<> inline unsigned short ceil ( unsigned short const& v ) { return v ; } template<> inline unsigned short modf ( unsigned short const& v , unsigned short& n ) { n = 0 ; return v ; } template<> inline unsigned short round( unsigned short const& v ) { return v ; } template<> inline unsigned short mod ( unsigned short const& a , unsigned short const& b ) { return (unsigned short)((unsigned int)a % (unsigned int)b) ; } template<> inline int abs ( int const& v ) { return std::abs ( v ) ; } template<> inline int floor( int const& v ) { return v ; } template<> inline int ceil ( int const& v ) { return v ; } template<> inline int modf ( int const& v , int& n ) { n = 0 ; return v ; } template<> inline int round( int const& v ) { return v ; } template<> inline int mod ( int const& a , int const& b ) { return a % b ; } template<> inline unsigned int abs ( unsigned int const& v ) { return std::abs ( v ) ; } template<> inline unsigned int floor( unsigned int const& v ) { return v ; } template<> inline unsigned int ceil ( unsigned int const& v ) { return v ; } template<> inline unsigned int modf ( unsigned int const& v , unsigned int& n ) { n = 0 ; return v ; } template<> inline unsigned int round( unsigned int const& v ) { return v ; } template<> inline unsigned int mod ( unsigned int const& a , unsigned int const& b ) { return a % b ; } template<> inline long abs ( long const& v ) { return std::abs ( v ) ; } template<> inline long floor( long const& v ) { return v ; } template<> inline long ceil ( long const& v ) { return v ; } template<> inline long modf ( long const& v , long& n ) { n = 0 ; return v ; } template<> inline long round( long const& v ) { return v ; } template<> inline long mod ( long const& a , long const& b ) { return a % b ; } template<> inline unsigned long abs ( unsigned long const& v ) { return std::abs ( v ) ; } template<> inline unsigned long floor( unsigned long const& v ) { return v ; } template<> inline unsigned long ceil ( unsigned long const& v ) { return v ; } template<> inline unsigned long modf ( unsigned long const& v , unsigned long& n ) { n = 0 ; return v ; } template<> inline unsigned long round( unsigned long const& v ) { return v ; } template<> inline unsigned long mod ( unsigned long const& a , unsigned long const& b ) { return a % b ; } template<> inline short cEpsilon () { return 0 ; } template<> inline unsigned short cEpsilon() { return 0 ; } template<> inline int cEpsilon () { return 0 ; } template<> inline unsigned int cEpsilon () { return 0 ; } template<> inline long cEpsilon () { return 0 ; } template<> inline unsigned long cEpsilon () { return 0 ; } // ////////////////////////////////////////////////////////////////////////////////////////// } //namespace gmath. // The following names are likely to be unique, so I put them in the global namespace. using gmath::cHalfPi ; using gmath::cPi ; using gmath::cThreeHalfPi ; using gmath::cTwoPi ; using gmath::cMinusHalfPi ; using gmath::cMinusPi ; using gmath::cMinusThreeHalfPi ; using gmath::cMinusTwoPi ; using gmath::cRadian ; using gmath::cEpsilon ; using gmath::cInfinite ; using gmath::equal_to_n ; using gmath::less_equal_n ; using gmath::greater_equal_n ; using gmath::less_n ; using gmath::greater_n ; using gmath::inRange ; using gmath::inOpenRange ; using gmath::inOpenCloseRange ; using gmath::inCloseOpenRange ; using gmath::zero_e ; using gmath::equal_e ; using gmath::lower_equal_e ; using gmath::higher_equal_e ; using gmath::lower_e ; using gmath::higher_e ; using gmath::inRange_e ; using gmath::inOpenRange_e ; using gmath::inOpenCloseRange_e ; using gmath::inCloseOpenRange_e ; #endif // ///////////////////////////////////////////////////////////////////////////////////////////////