/***************************************************************************\ |* Function Parser for C++ v4.5.2 *| |*-------------------------------------------------------------------------*| |* Copyright: Juha Nieminen, Joel Yliluoma *| |* *| |* This library is distributed under the terms of the *| |* GNU Lesser General Public License version 3. *| |* (See lgpl.txt and gpl.txt for the license text.) *| \***************************************************************************/ // NOTE: // This file contains only internal types for the function parser library. // You don't need to include this file in your code. Include "fparser.hh" // only. #ifndef ONCE_FPARSER_AUX_H_ #define ONCE_FPARSER_AUX_H_ #include "fptypes.hh" #include #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE #include "mpfr/MpfrFloat.hh" #endif #ifdef FP_SUPPORT_GMP_INT_TYPE #include "mpfr/GmpInt.hh" #endif #ifdef FP_SUPPORT_COMPLEX_NUMBERS #include #endif #ifdef ONCE_FPARSER_H_ namespace FUNCTIONPARSERTYPES { template struct IsIntType { enum { result = false }; }; template<> struct IsIntType { enum { result = true }; }; #ifdef FP_SUPPORT_GMP_INT_TYPE template<> struct IsIntType { enum { result = true }; }; #endif template struct IsComplexType { enum { result = false }; }; #ifdef FP_SUPPORT_COMPLEX_NUMBERS template struct IsComplexType > { enum { result = true }; }; #endif //========================================================================== // Constants //========================================================================== template inline Value_t fp_const_pi() // CONSTANT_PI { return Value_t(3.1415926535897932384626433832795028841971693993751L); } template inline Value_t fp_const_e() // CONSTANT_E { return Value_t(2.7182818284590452353602874713526624977572L); } template inline Value_t fp_const_einv() // CONSTANT_EI { return Value_t(0.367879441171442321595523770161460867445811131L); } template inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI { return Value_t(0.69314718055994530941723212145817656807550013436025525412L); } template inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI { return Value_t(2.302585092994045684017991454684364207601101488628772976L); } template inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E { return Value_t(1.442695040888963407359924681001892137426645954L); } template inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E { return Value_t(0.434294481903251827651128918916605082294397L); } template inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR { static const Value_t factor = fp_const_pi() / Value_t(180); // to rad from deg return factor; } template inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD { static const Value_t factor = Value_t(180) / fp_const_pi(); // to deg from rad return factor; } #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE template<> inline MpfrFloat fp_const_pi() { return MpfrFloat::const_pi(); } template<> inline MpfrFloat fp_const_e() { return MpfrFloat::const_e(); } template<> inline MpfrFloat fp_const_einv() { return MpfrFloat(1) / MpfrFloat::const_e(); } template<> inline MpfrFloat fp_const_log2() { return MpfrFloat::const_log2(); } /* template<> inline MpfrFloat fp_const_log10() { return fp_log(MpfrFloat(10)); } template<> inline MpfrFloat fp_const_log2inv() { return MpfrFloat(1) / MpfrFloat::const_log2(); } template<> inline MpfrFloat fp_const_log10inv() { return fp_log10(MpfrFloat::const_e()); } */ #endif //========================================================================== // Generic math functions //========================================================================== template inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); } template inline Value_t fp_acos(const Value_t& x) { return std::acos(x); } template inline Value_t fp_asin(const Value_t& x) { return std::asin(x); } template inline Value_t fp_atan(const Value_t& x) { return std::atan(x); } template inline Value_t fp_atan2(const Value_t& x, const Value_t& y) { return std::atan2(x, y); } template inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); } template inline Value_t fp_cos(const Value_t& x) { return std::cos(x); } template inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); } template inline Value_t fp_exp(const Value_t& x) { return std::exp(x); } template inline Value_t fp_floor(const Value_t& x) { return std::floor(x); } template inline Value_t fp_log(const Value_t& x) { return std::log(x); } template inline Value_t fp_mod(const Value_t& x, const Value_t& y) { return std::fmod(x, y); } template inline Value_t fp_sin(const Value_t& x) { return std::sin(x); } template inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); } template inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); } template inline Value_t fp_tan(const Value_t& x) { return std::tan(x); } template inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); } #ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS template inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); } template inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); } template inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); } #else template inline Value_t fp_asinh(const Value_t& x) { return fp_log(x + fp_sqrt(x*x + Value_t(1))); } template inline Value_t fp_acosh(const Value_t& x) { return fp_log(x + fp_sqrt(x*x - Value_t(1))); } template inline Value_t fp_atanh(const Value_t& x) { return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); // Note: x = +1 causes division by zero // x = -1 causes log(0) // Thus, x must not be +-1 } #endif // FP_SUPPORT_ASINH #ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS template inline Value_t fp_hypot(const Value_t& x, const Value_t& y) { return std::hypot(x,y); } template inline std::complex fp_hypot (const std::complex& x, const std::complex& y) { return fp_sqrt(x*x + y*y); } #else template inline Value_t fp_hypot(const Value_t& x, const Value_t& y) { return fp_sqrt(x*x + y*y); } #endif template inline Value_t fp_pow_base(const Value_t& x, const Value_t& y) { return std::pow(x, y); } #ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS template inline Value_t fp_log2(const Value_t& x) { return std::log2(x); } template inline std::complex fp_log2(const std::complex& x) { return fp_log(x) * fp_const_log2inv(); } #else template inline Value_t fp_log2(const Value_t& x) { return fp_log(x) * fp_const_log2inv(); } #endif // FP_SUPPORT_LOG2 template inline Value_t fp_log10(const Value_t& x) { return fp_log(x) * fp_const_log10inv(); } template inline Value_t fp_trunc(const Value_t& x) { return x < Value_t() ? fp_ceil(x) : fp_floor(x); } template inline Value_t fp_int(const Value_t& x) { return x < Value_t() ? fp_ceil(x - Value_t(0.5)) : fp_floor(x + Value_t(0.5)); } template inline void fp_sinCos(Value_t& sinvalue, Value_t& cosvalue, const Value_t& param) { // Assuming that "cosvalue" and "param" do not // overlap, but "sinvalue" and "param" may. cosvalue = fp_cos(param); sinvalue = fp_sin(param); } template inline void fp_sinhCosh(Value_t& sinhvalue, Value_t& coshvalue, const Value_t& param) { const Value_t ex(fp_exp(param)), emx(fp_exp(-param)); sinhvalue = Value_t(0.5)*(ex-emx); coshvalue = Value_t(0.5)*(ex+emx); } template struct Epsilon { static Value_t value; static Value_t defaultValue() { return 0; } }; template<> inline double Epsilon::defaultValue() { return 1E-12; } template<> inline float Epsilon::defaultValue() { return 1E-5F; } template<> inline long double Epsilon::defaultValue() { return 1E-14L; } template<> inline std::complex Epsilon >::defaultValue() { return 1E-12; } template<> inline std::complex Epsilon >::defaultValue() { return 1E-5F; } template<> inline std::complex Epsilon >::defaultValue() { return 1E-14L; } #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE template<> inline MpfrFloat Epsilon::defaultValue() { return MpfrFloat::someEpsilon(); } #endif template Value_t Epsilon::value = Epsilon::defaultValue(); #ifdef _GNU_SOURCE inline void fp_sinCos(double& sin, double& cos, const double& a) { sincos(a, &sin, &cos); } inline void fp_sinCos(float& sin, float& cos, const float& a) { sincosf(a, &sin, &cos); } inline void fp_sinCos(long double& sin, long double& cos, const long double& a) { sincosl(a, &sin, &cos); } #endif // ------------------------------------------------------------------------- // Long int // ------------------------------------------------------------------------- inline long fp_abs(const long& x) { return x < 0 ? -x : x; } inline long fp_acos(const long&) { return 0; } inline long fp_asin(const long&) { return 0; } inline long fp_atan(const long&) { return 0; } inline long fp_atan2(const long&, const long&) { return 0; } inline long fp_cbrt(const long&) { return 0; } inline long fp_ceil(const long& x) { return x; } inline long fp_cos(const long&) { return 0; } inline long fp_cosh(const long&) { return 0; } inline long fp_exp(const long&) { return 0; } inline long fp_exp2(const long&) { return 0; } inline long fp_floor(const long& x) { return x; } inline long fp_log(const long&) { return 0; } inline long fp_log2(const long&) { return 0; } inline long fp_log10(const long&) { return 0; } inline long fp_mod(const long& x, const long& y) { return x % y; } inline long fp_pow(const long&, const long&) { return 0; } inline long fp_sin(const long&) { return 0; } inline long fp_sinh(const long&) { return 0; } inline long fp_sqrt(const long&) { return 1; } inline long fp_tan(const long&) { return 0; } inline long fp_tanh(const long&) { return 0; } inline long fp_asinh(const long&) { return 0; } inline long fp_acosh(const long&) { return 0; } inline long fp_atanh(const long&) { return 0; } inline long fp_pow_base(const long&, const long&) { return 0; } inline void fp_sinCos(long&, long&, const long&) {} inline void fp_sinhCosh(long&, long&, const long&) {} //template<> inline long fp_epsilon() { return 0; } // ------------------------------------------------------------------------- // MpfrFloat // ------------------------------------------------------------------------- #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); } inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); } inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); } inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); } inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); } inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); } inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::atan2(x, y); } inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); } inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); } inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); } inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); } inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); } inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); } inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); } inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); } inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::hypot(x, y); } inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); } inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); } inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); } inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); } inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; } inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); } inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); } inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); } inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); } inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); } inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); } inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } inline void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a) { MpfrFloat::sincos(a, sin, cos); } inline void fp_sinhCosh(MpfrFloat& sinhvalue, MpfrFloat& coshvalue, const MpfrFloat& param) { const MpfrFloat paramCopy = param; sinhvalue = fp_sinh(paramCopy); coshvalue = fp_cosh(paramCopy); } #endif // FP_SUPPORT_MPFR_FLOAT_TYPE // ------------------------------------------------------------------------- // GMP int // ------------------------------------------------------------------------- #ifdef FP_SUPPORT_GMP_INT_TYPE inline GmpInt fp_abs(const GmpInt& x) { return GmpInt::abs(x); } inline GmpInt fp_acos(const GmpInt&) { return 0; } inline GmpInt fp_acosh(const GmpInt&) { return 0; } inline GmpInt fp_asin(const GmpInt&) { return 0; } inline GmpInt fp_asinh(const GmpInt&) { return 0; } inline GmpInt fp_atan(const GmpInt&) { return 0; } inline GmpInt fp_atan2(const GmpInt&, const GmpInt&) { return 0; } inline GmpInt fp_atanh(const GmpInt&) { return 0; } inline GmpInt fp_cbrt(const GmpInt&) { return 0; } inline GmpInt fp_ceil(const GmpInt& x) { return x; } inline GmpInt fp_cos(const GmpInt&) { return 0; } inline GmpInt fp_cosh(const GmpInt&) { return 0; } inline GmpInt fp_exp(const GmpInt&) { return 0; } inline GmpInt fp_exp2(const GmpInt&) { return 0; } inline GmpInt fp_floor(const GmpInt& x) { return x; } inline GmpInt fp_hypot(const GmpInt&, const GmpInt&) { return 0; } inline GmpInt fp_int(const GmpInt& x) { return x; } inline GmpInt fp_log(const GmpInt&) { return 0; } inline GmpInt fp_log2(const GmpInt&) { return 0; } inline GmpInt fp_log10(const GmpInt&) { return 0; } inline GmpInt fp_mod(const GmpInt& x, const GmpInt& y) { return x % y; } inline GmpInt fp_pow(const GmpInt&, const GmpInt&) { return 0; } inline GmpInt fp_sin(const GmpInt&) { return 0; } inline GmpInt fp_sinh(const GmpInt&) { return 0; } inline GmpInt fp_sqrt(const GmpInt&) { return 0; } inline GmpInt fp_tan(const GmpInt&) { return 0; } inline GmpInt fp_tanh(const GmpInt&) { return 0; } inline GmpInt fp_trunc(const GmpInt& x) { return x; } inline GmpInt fp_pow_base(const GmpInt&, const GmpInt&) { return 0; } inline void fp_sinCos(GmpInt&, GmpInt&, const GmpInt&) {} inline void fp_sinhCosh(GmpInt&, GmpInt&, const GmpInt&) {} #endif // FP_SUPPORT_GMP_INT_TYPE #ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS template inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); } #else template inline Value_t fp_cbrt(const Value_t& x) { return (x > Value_t() ? fp_exp(fp_log( x) / Value_t(3)) : x < Value_t() ? -fp_exp(fp_log(-x) / Value_t(3)) : Value_t()); } #endif // ------------------------------------------------------------------------- // Synthetic functions and fallbacks for when an optimized // implementation or a library function is not available // ------------------------------------------------------------------------- template inline Value_t fp_arg(const Value_t& x); template inline Value_t fp_exp2(const Value_t& x); template inline Value_t fp_int(const Value_t& x); template inline Value_t fp_trunc(const Value_t& x); template inline void fp_sinCos(Value_t& , Value_t& , const Value_t& ); template inline void fp_sinhCosh(Value_t& , Value_t& , const Value_t& ); #ifdef FP_SUPPORT_COMPLEX_NUMBERS /* NOTE: Complex multiplication of a and b can be done with: tmp = b.real * (a.real + a.imag) result.real = tmp - a.imag * (b.real + b.imag) result.imag = tmp + a.real * (b.imag - b.real) This has fewer multiplications than the standard algorithm. Take note, if you support mpfr complex one day. */ template struct FP_ProbablyHasFastLibcComplex { enum { result = false }; }; /* The generic sqrt() etc. implementations in libstdc++ * are very plain and non-optimized; however, it contains * callbacks to libc complex math functions where possible, * and I suspect that those may actually be well optimized. * So we use std:: functions when we suspect they may be fast, * and otherwise we use our own optimized implementations. */ #ifdef __GNUC__ template<> struct FP_ProbablyHasFastLibcComplex { enum { result = true }; }; template<> struct FP_ProbablyHasFastLibcComplex { enum { result = true }; }; template<> struct FP_ProbablyHasFastLibcComplex { enum { result = true }; }; #endif template inline const std::complex fp_make_imag(const std::complex& v) { return std::complex ( T(), v.real() ); } template inline std::complex fp_real(const std::complex& x) { return x.real(); } template inline std::complex fp_imag(const std::complex& x) { return x.imag(); } template inline std::complex fp_arg(const std::complex& x) { return std::arg(x); } template inline std::complex fp_conj(const std::complex& x) { return std::conj(x); } template inline std::complex fp_polar(const T& x, const T& y) { T si, co; fp_sinCos(si, co, y); return std::complex (x*co, x*si); } template inline std::complex fp_polar(const std::complex& x, const std::complex& y) { // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers return fp_polar (x.real(), y.real()); //return std::polar(x.real(), y.real()); //return x * (fp_cos(y) + (std::complex(0,1) * fp_sin(y)); } // These provide fallbacks in case there's no library function template inline std::complex fp_floor(const std::complex& x) { return std::complex (fp_floor(x.real()), fp_floor(x.imag())); } template inline std::complex fp_trunc(const std::complex& x) { return std::complex (fp_trunc(x.real()), fp_trunc(x.imag())); } template inline std::complex fp_int(const std::complex& x) { return std::complex (fp_int(x.real()), fp_int(x.imag())); } template inline std::complex fp_ceil(const std::complex& x) { return std::complex (fp_ceil(x.real()), fp_ceil(x.imag())); } template inline std::complex fp_abs(const std::complex& x) { return std::abs(x); //T extent = fp_max(fp_abs(x.real()), fp_abs(x.imag())); //if(extent == T()) return x; //return extent * fp_hypot(x.real() / extent, x.imag() / extent); } template inline std::complex fp_exp(const std::complex& x) { if(FP_ProbablyHasFastLibcComplex::result) return std::exp(x); return fp_polar(fp_exp(x.real()), x.imag()); } template inline std::complex fp_log(const std::complex& x) { if(FP_ProbablyHasFastLibcComplex::result) return std::log(x); // log(abs(x)) + i*arg(x) // log(Xr^2+Xi^2)*0.5 + i*arg(x) if(x.imag()==T()) return std::complex( fp_log(fp_abs(x.real())), fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here! return std::complex( fp_log(std::norm(x)) * T(0.5), fp_arg(x).real() ); } template inline std::complex fp_sqrt(const std::complex& x) { if(FP_ProbablyHasFastLibcComplex::result) return std::sqrt(x); return fp_polar (fp_sqrt(fp_abs(x).real()), T(0.5)*fp_arg(x).real()); } template inline std::complex fp_acos(const std::complex& x) { // -i * log(x + i * sqrt(1 - x^2)) const std::complex i (T(), T(1)); return -i * fp_log(x + i * fp_sqrt(T(1) - x*x)); // Note: Real version of acos() cannot handle |x| > 1, // because it would cause sqrt(negative value). } template inline std::complex fp_asin(const std::complex& x) { // -i * log(i*x + sqrt(1 - x^2)) const std::complex i (T(), T(1)); return -i * fp_log(i*x + fp_sqrt(T(1) - x*x)); // Note: Real version of asin() cannot handle |x| > 1, // because it would cause sqrt(negative value). } template inline std::complex fp_atan(const std::complex& x) { // 0.5i * (log(1-i*x) - log(1+i*x)) // -0.5i * log( (1+i*x) / (1-i*x) ) const std::complex i (T(), T(1)); return (T(-0.5)*i) * fp_log( (T(1)+i*x) / (T(1)-i*x) ); // Note: x = -1i causes division by zero // x = +1i causes log(0) // Thus, x must not be +-1i } template inline std::complex fp_cos(const std::complex& x) { return std::cos(x); // // (exp(i*x) + exp(-i*x)) / (2) // //const std::complex i (T(), T(1)); // //return (fp_exp(i*x) + fp_exp(-i*x)) * T(0.5); // // Also: cos(Xr)*cosh(Xi) - i*sin(Xr)*sinh(Xi) // return std::complex ( // fp_cos(x.real())*fp_cosh(x.imag()), // -fp_sin(x.real())*fp_sinh(x.imag())); } template inline std::complex fp_sin(const std::complex& x) { return std::sin(x); // // (exp(i*x) - exp(-i*x)) / (2i) // //const std::complex i (T(), T(1)); // //return (fp_exp(i*x) - fp_exp(-i*x)) * (T(-0.5)*i); // // Also: sin(Xr)*cosh(Xi) + cos(Xr)*sinh(Xi) // return std::complex ( // fp_sin(x.real())*fp_cosh(x.imag()), // fp_cos(x.real())*fp_sinh(x.imag())); } template inline void fp_sinCos( std::complex& sinvalue, std::complex& cosvalue, const std::complex& x) { //const std::complex i (T(), T(1)), expix(fp_exp(i*x)), expmix(fp_exp((-i)*x)); //cosvalue = (expix + expmix) * T(0.5); //sinvalue = (expix - expmix) * (i*T(-0.5)); // The above expands to the following: T srx, crx; fp_sinCos(srx, crx, x.real()); T six, cix; fp_sinhCosh(six, cix, x.imag()); sinvalue = std::complex(srx*cix, crx*six); cosvalue = std::complex(crx*cix, -srx*six); } template inline void fp_sinhCosh( std::complex& sinhvalue, std::complex& coshvalue, const std::complex& x) { T srx, crx; fp_sinhCosh(srx, crx, x.real()); T six, cix; fp_sinCos(six, cix, x.imag()); sinhvalue = std::complex(srx*cix, crx*six); coshvalue = std::complex(crx*cix, srx*six); } template inline std::complex fp_tan(const std::complex& x) { return std::tan(x); //std::complex si, co; //fp_sinCos(si, co, x); //return si/co; // // (i-i*exp(2i*x)) / (exp(2i*x)+1) // const std::complex i (T(), T(1)), exp2ix=fp_exp((2*i)*x); // return (i-i*exp2ix) / (exp2ix+T(1)); // // Also: sin(x)/cos(y) // // return fp_sin(x)/fp_cos(x); } template inline std::complex fp_cosh(const std::complex& x) { return std::cosh(x); // // (exp(x) + exp(-x)) * 0.5 // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi) // return std::complex ( // fp_cosh(x.real())*fp_cos(x.imag()), // fp_sinh(x.real())*fp_sin(x.imag())); } template inline std::complex fp_sinh(const std::complex& x) { return std::sinh(x); // // (exp(x) - exp(-x)) * 0.5 // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi) // return std::complex ( // fp_sinh(x.real())*fp_cos(x.imag()), // fp_cosh(x.real())*fp_sin(x.imag())); } template inline std::complex fp_tanh(const std::complex& x) { return std::tanh(x); //std::complex si, co; //fp_sinhCosh(si, co, x); //return si/co; // // (exp(2*x)-1) / (exp(2*x)+1) // // Also: sinh(x)/tanh(x) // const std::complex exp2x=fp_exp(x+x); // return (exp2x-T(1)) / (exp2x+T(1)); } #ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS template inline std::complex fp_acosh(const std::complex& x) { return fp_log(x + fp_sqrt(x*x - std::complex(1))); } template inline std::complex fp_asinh(const std::complex& x) { return fp_log(x + fp_sqrt(x*x + std::complex(1))); } template inline std::complex fp_atanh(const std::complex& x) { return fp_log( (std::complex(1)+x) / (std::complex(1)-x)) * std::complex(0.5); } #endif template inline std::complex fp_pow(const std::complex& x, const std::complex& y) { // return std::pow(x,y); // With complex numbers, pow(x,y) can be solved with // the general formula: exp(y*log(x)). It handles // all special cases gracefully. // It expands to the following: // A) // t1 = log(x) // t2 = y * t1 // res = exp(t2) // B) // t1.r = log(x.r * x.r + x.i * x.i) * 0.5 \ fp_log() // t1.i = atan2(x.i, x.r) / // t2.r = y.r*t1.r - y.i*t1.i \ multiplication // t2.i = y.r*t1.i + y.i*t1.r / // rho = exp(t2.r) \ fp_exp() // theta = t2.i / // res.r = rho * cos(theta) \ fp_polar(), called from // res.i = rho * sin(theta) / fp_exp(). Uses sincos(). // Aside from the common "norm" calculation in atan2() // and in the log parameter, both of which are part of fp_log(), // there does not seem to be any incentive to break this // function down further; it would not help optimizing it. // However, we do handle the following special cases: // // When x is real (positive or negative): // t1.r = log(abs(x.r)) // t1.i = x.r<0 ? -pi : 0 // When y is real: // t2.r = y.r * t1.r // t2.i = y.r * t1.i const std::complex t = (x.imag() != T()) ? fp_log(x) : std::complex (fp_log(fp_abs(x.real())), fp_arg(x.real())); // Note: Uses real-value fp_arg() here! return y.imag() != T() ? fp_exp(y * t) : fp_polar (fp_exp(y.real()*t.real()), y.real()*t.imag()); } template inline std::complex fp_cbrt(const std::complex& x) { // For real numbers, prefer giving a real solution // rather than a complex solution. // For example, cbrt(-3) has the following three solutions: // A) 0.7211247966535 + 1.2490247864016i // B) 0.7211247966535 - 1.2490247864016i // C) -1.442249593307 // exp(log(x)/3) gives A, but we prefer to give C. if(x.imag() == T()) return fp_cbrt(x.real()); const std::complex t(fp_log(x)); return fp_polar (fp_exp(t.real() / T(3)), t.imag() / T(3)); } template inline std::complex fp_exp2(const std::complex& x) { // pow(2, x) // polar(2^Xr, Xi*log(2)) return fp_polar (fp_exp2(x.real()), x.imag()*fp_const_log2()); } template inline std::complex fp_mod(const std::complex& x, const std::complex& y) { // Modulo function is probably not defined for complex numbers. // But we do our best to calculate it the same way as it is done // with real numbers, so that at least it is in some way "consistent". if(y.imag() == 0) return fp_mod(x.real(), y.real()); // optimization std::complex n = fp_trunc(x / y); return x - n * y; } /* libstdc++ already defines a streaming operator for complex values, * but we redefine our own that it is compatible with the input * accepted by fparser. I.e. instead of (5,3) we now get (5+3i), * and instead of (-4,0) we now get -4. */ template inline std::ostream& operator<<(std::ostream& os, const std::complex& value) { if(value.imag() == T()) return os << value.real(); if(value.real() == T()) return os << value.imag() << 'i'; if(value.imag() < T()) return os << '(' << value.real() << "-" << -value.imag() << "i)"; else return os << '(' << value.real() << "+" << value.imag() << "i)"; } /* Less-than or greater-than operators are not technically defined * for Complex types. However, in fparser and its tool set, these * operators are widely required to be present. * Our implementation here is based on converting the complex number * into a scalar and the doing a scalar comparison on the value. * The means by which the number is changed into a scalar is based * on the following principles: * - Does not introduce unjustified amounts of extra inaccuracy * - Is transparent to purely real values * (this disqualifies something like x.real() + x.imag()) * - Does not ignore the imaginary value completely * (this may be relevant especially in testbed) * - Is not so complicated that it would slow down a great deal * * Basically our formula here is the same as std::abs(), * except that it keeps the sign of the original real number, * and it does not do a sqrt() calculation that is not really * needed because we are only interested in the relative magnitudes. * * Equality and nonequality operators must not need to be overloaded. * They are already implemented in standard, and we must * not introduce flawed equality assumptions. */ template inline T fp_complexScalarize(const std::complex& x) { T res(std::norm(x)); if(x.real() < T()) res = -res; return res; } template inline T fp_realComplexScalarize(const T& x) { T res(x*x); if(x < T()) res = -res; return res; } // { return x.real() * (T(1.0) + fp_abs(x.imag())); } #define d(op) \ template \ inline bool operator op (const std::complex& x, T y) \ { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \ template \ inline bool operator op (const std::complex& x, const std::complex& y) \ { return fp_complexScalarize(x) op \ fp_complexScalarize(y); } \ template \ inline bool operator op (T x, const std::complex& y) \ { return fp_realComplexScalarize(x) op fp_complexScalarize(y); } d( < ) d( <= ) d( > ) d( >= ) #undef d #endif template inline Value_t fp_real(const Value_t& x) { return x; } template inline Value_t fp_imag(const Value_t& ) { return Value_t(); } template inline Value_t fp_arg(const Value_t& x) { return x < Value_t() ? -fp_const_pi() : Value_t(); } template inline Value_t fp_conj(const Value_t& x) { return x; } template inline Value_t fp_polar(const Value_t& x, const Value_t& y) { return x * fp_cos(y); } // This is of course a meaningless function. template inline std::complex fp_atan2(const std::complex& y, const std::complex& x) { if(y == Value_t()) return fp_arg(x); if(x == Value_t()) return fp_const_pi() * Value_t(-0.5); // 2*atan(y / (sqrt(x^2+y^2) + x) ) // 2*atan( (sqrt(x^2+y^2) - x) / y) std::complex res( fp_atan(y / (fp_hypot(x,y) + x)) ); return res+res; } // ------------------------------------------------------------------------- // Comparison // ------------------------------------------------------------------------- template inline bool fp_equal(const Value_t& x, const Value_t& y) { return IsIntType::result ? (x == y) : (fp_abs(x - y) <= Epsilon::value); } template inline bool fp_nequal(const Value_t& x, const Value_t& y) { return IsIntType::result ? (x != y) : (fp_abs(x - y) > Epsilon::value); } template inline bool fp_less(const Value_t& x, const Value_t& y) { return IsIntType::result ? (x < y) : (x < y - Epsilon::value); } template inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) { return IsIntType::result ? (x <= y) : (x <= y + Epsilon::value); } template inline bool fp_greater(const Value_t& x, const Value_t& y) { return fp_less(y, x); } template inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y) { return fp_lessOrEq(y, x); } template inline bool fp_truth(const Value_t& d) { return IsIntType::result ? d != Value_t() : fp_abs(d) >= Value_t(0.5); } template inline bool fp_absTruth(const Value_t& abs_d) { return IsIntType::result ? abs_d > Value_t() : abs_d >= Value_t(0.5); } template inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2) { return d1 inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2) { return d1>d2 ? d1 : d2; } template inline const Value_t fp_not(const Value_t& b) { return Value_t(!fp_truth(b)); } template inline const Value_t fp_notNot(const Value_t& b) { return Value_t(fp_truth(b)); } template inline const Value_t fp_absNot(const Value_t& b) { return Value_t(!fp_absTruth(b)); } template inline const Value_t fp_absNotNot(const Value_t& b) { return Value_t(fp_absTruth(b)); } template inline const Value_t fp_and(const Value_t& a, const Value_t& b) { return Value_t(fp_truth(a) && fp_truth(b)); } template inline const Value_t fp_or(const Value_t& a, const Value_t& b) { return Value_t(fp_truth(a) || fp_truth(b)); } template inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b) { return Value_t(fp_absTruth(a) && fp_absTruth(b)); } template inline const Value_t fp_absOr(const Value_t& a, const Value_t& b) { return Value_t(fp_absTruth(a) || fp_absTruth(b)); } template inline const Value_t fp_make_imag(const Value_t& ) // Imaginary 1. In real mode, always zero. { return Value_t(); } ///////////// /* Opcode analysis functions are used by fp_opcode_add.inc */ /* Moved here from fparser.cc because fp_opcode_add.inc * is also now included by fpoptimizer.cc */ bool IsLogicalOpcode(unsigned op); bool IsComparisonOpcode(unsigned op); unsigned OppositeComparisonOpcode(unsigned op); bool IsNeverNegativeValueOpcode(unsigned op); bool IsAlwaysIntegerOpcode(unsigned op); bool IsUnaryOpcode(unsigned op); bool IsBinaryOpcode(unsigned op); bool IsVarOpcode(unsigned op); bool IsCommutativeOrParamSwappableBinaryOpcode(unsigned op); unsigned GetParamSwappedBinaryOpcode(unsigned op); template bool HasInvalidRangesOpcode(unsigned op); template inline Value_t DegreesToRadians(const Value_t& degrees) { return degrees * fp_const_deg_to_rad(); } template inline Value_t RadiansToDegrees(const Value_t& radians) { return radians * fp_const_rad_to_deg(); } template inline long makeLongInteger(const Value_t& value) { return (long) fp_int(value); } #ifdef FP_SUPPORT_COMPLEX_NUMBERS template inline long makeLongInteger(const std::complex& value) { return (long) fp_int( std::abs(value) ); } #endif // Is value an integer that fits in "long" datatype? template inline bool isLongInteger(const Value_t& value) { return value == Value_t( makeLongInteger(value) ); } template inline bool isOddInteger(const Value_t& value) { const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5); return fp_equal(halfValue, fp_floor(halfValue)); } template inline bool isEvenInteger(const Value_t& value) { const Value_t halfValue = value * Value_t(0.5); return fp_equal(halfValue, fp_floor(halfValue)); } template inline bool isInteger(const Value_t& value) { return fp_equal(value, fp_floor(value)); } #ifdef FP_SUPPORT_LONG_INT_TYPE template<> inline bool isEvenInteger(const long& value) { return value%2 == 0; } template<> inline bool isInteger(const long&) { return true; } template<> inline bool isLongInteger(const long&) { return true; } template<> inline long makeLongInteger(const long& value) { return value; } #endif #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE template<> inline bool isInteger(const MpfrFloat& value) { return value.isInteger(); } template<> inline bool isEvenInteger(const MpfrFloat& value) { return isInteger(value) && value%2 == 0; } template<> inline long makeLongInteger(const MpfrFloat& value) { return (long) value.toInt(); } #endif #ifdef FP_SUPPORT_GMP_INT_TYPE template<> inline bool isEvenInteger(const GmpInt& value) { return value%2 == 0; } template<> inline bool isInteger(const GmpInt&) { return true; } template<> inline long makeLongInteger(const GmpInt& value) { return (long) value.toInt(); } #endif #ifdef FP_SUPPORT_LONG_INT_TYPE template<> inline bool isOddInteger(const long& value) { return value%2 != 0; } #endif #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE template<> inline bool isOddInteger(const MpfrFloat& value) { return value.isInteger() && value%2 != 0; } #endif #ifdef FP_SUPPORT_GMP_INT_TYPE template<> inline bool isOddInteger(const GmpInt& value) { return value%2 != 0; } #endif // ------------------------------------------------------------------------- // fp_pow // ------------------------------------------------------------------------- // Commented versions in fparser.cc template inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y) { return fp_exp(fp_log(x) * y); } template inline Value_t fp_powi(Value_t x, unsigned long y) { Value_t result(1); while(y != 0) { if(y & 1) { result *= x; y -= 1; } else { x *= x; y /= 2; } } return result; } template Value_t fp_pow(const Value_t& x, const Value_t& y) { if(x == Value_t(1)) return Value_t(1); if(isLongInteger(y)) { if(y >= Value_t(0)) return fp_powi(x, makeLongInteger(y)); else return Value_t(1) / fp_powi(x, -makeLongInteger(y)); } if(y >= Value_t(0)) { if(x > Value_t(0)) return fp_pow_with_exp_log(x, y); if(x == Value_t(0)) return Value_t(0); if(!isInteger(y*Value_t(16))) return -fp_pow_with_exp_log(-x, y); } else { if(x > Value_t(0)) return fp_pow_with_exp_log(Value_t(1) / x, -y); if(x < Value_t(0)) { if(!isInteger(y*Value_t(-16))) return -fp_pow_with_exp_log(Value_t(-1) / x, -y); } } return fp_pow_base(x, y); } template inline Value_t fp_exp2(const Value_t& x) { return fp_pow(Value_t(2), x); } } // namespace FUNCTIONPARSERTYPES #endif // ONCE_FPARSER_H_ #endif // ONCE_FPARSER_AUX_H_