summaryrefslogtreecommitdiff
path: root/fparser/extrasrc/fpaux.hh
diff options
context:
space:
mode:
Diffstat (limited to 'fparser/extrasrc/fpaux.hh')
-rw-r--r--fparser/extrasrc/fpaux.hh1238
1 files changed, 1238 insertions, 0 deletions
diff --git a/fparser/extrasrc/fpaux.hh b/fparser/extrasrc/fpaux.hh
new file mode 100644
index 0000000..fe2011c
--- /dev/null
+++ b/fparser/extrasrc/fpaux.hh
@@ -0,0 +1,1238 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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 <cmath>
+
+#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 <complex>
+#endif
+
+#ifdef ONCE_FPARSER_H_
+namespace FUNCTIONPARSERTYPES
+{
+ template<typename>
+ struct IsIntType
+ {
+ enum { result = false };
+ };
+ template<>
+ struct IsIntType<long>
+ {
+ enum { result = true };
+ };
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+ template<>
+ struct IsIntType<GmpInt>
+ {
+ enum { result = true };
+ };
+#endif
+
+ template<typename>
+ struct IsComplexType
+ {
+ enum { result = false };
+ };
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ template<typename T>
+ struct IsComplexType<std::complex<T> >
+ {
+ enum { result = true };
+ };
+#endif
+
+
+//==========================================================================
+// Constants
+//==========================================================================
+ template<typename Value_t>
+ inline Value_t fp_const_pi() // CONSTANT_PI
+ {
+ return Value_t(3.1415926535897932384626433832795028841971693993751L);
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_const_e() // CONSTANT_E
+ {
+ return Value_t(2.7182818284590452353602874713526624977572L);
+ }
+ template<typename Value_t>
+ inline Value_t fp_const_einv() // CONSTANT_EI
+ {
+ return Value_t(0.367879441171442321595523770161460867445811131L);
+ }
+ template<typename Value_t>
+ inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI
+ {
+ return Value_t(0.69314718055994530941723212145817656807550013436025525412L);
+ }
+ template<typename Value_t>
+ inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI
+ {
+ return Value_t(2.302585092994045684017991454684364207601101488628772976L);
+ }
+ template<typename Value_t>
+ inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E
+ {
+ return Value_t(1.442695040888963407359924681001892137426645954L);
+ }
+ template<typename Value_t>
+ inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E
+ {
+ return Value_t(0.434294481903251827651128918916605082294397L);
+ }
+
+ template<typename Value_t>
+ inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR
+ {
+ static const Value_t factor = fp_const_pi<Value_t>() / Value_t(180); // to rad from deg
+ return factor;
+ }
+
+ template<typename Value_t>
+ inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD
+ {
+ static const Value_t factor = Value_t(180) / fp_const_pi<Value_t>(); // to deg from rad
+ return factor;
+ }
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+ template<>
+ inline MpfrFloat fp_const_pi<MpfrFloat>() { return MpfrFloat::const_pi(); }
+
+ template<>
+ inline MpfrFloat fp_const_e<MpfrFloat>() { return MpfrFloat::const_e(); }
+
+ template<>
+ inline MpfrFloat fp_const_einv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_e(); }
+
+ template<>
+ inline MpfrFloat fp_const_log2<MpfrFloat>() { return MpfrFloat::const_log2(); }
+
+ /*
+ template<>
+ inline MpfrFloat fp_const_log10<MpfrFloat>() { return fp_log(MpfrFloat(10)); }
+
+ template<>
+ inline MpfrFloat fp_const_log2inv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_log2(); }
+
+ template<>
+ inline MpfrFloat fp_const_log10inv<MpfrFloat>() { return fp_log10(MpfrFloat::const_e()); }
+ */
+#endif
+
+
+//==========================================================================
+// Generic math functions
+//==========================================================================
+ template<typename Value_t>
+ inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_acos(const Value_t& x) { return std::acos(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_asin(const Value_t& x) { return std::asin(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atan(const Value_t& x) { return std::atan(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atan2(const Value_t& x, const Value_t& y)
+ { return std::atan2(x, y); }
+
+ template<typename Value_t>
+ inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_cos(const Value_t& x) { return std::cos(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_exp(const Value_t& x) { return std::exp(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_floor(const Value_t& x) { return std::floor(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_log(const Value_t& x) { return std::log(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_mod(const Value_t& x, const Value_t& y)
+ { return std::fmod(x, y); }
+
+ template<typename Value_t>
+ inline Value_t fp_sin(const Value_t& x) { return std::sin(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_tan(const Value_t& x) { return std::tan(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); }
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename Value_t>
+ inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_asinh(const Value_t& x)
+ { return fp_log(x + fp_sqrt(x*x + Value_t(1))); }
+
+ template<typename Value_t>
+ inline Value_t fp_acosh(const Value_t& x)
+ { return fp_log(x + fp_sqrt(x*x - Value_t(1))); }
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ inline Value_t fp_hypot(const Value_t& x, const Value_t& y)
+ { return std::hypot(x,y); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_hypot(const Value_t& x, const Value_t& y)
+ { return fp_sqrt(x*x + y*y); }
+#endif
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ inline Value_t fp_log2(const Value_t& x) { return std::log2(x); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_log2(const Value_t& x)
+ {
+ return fp_log(x) * fp_const_log2inv<Value_t>();
+ }
+#endif // FP_SUPPORT_LOG2
+
+ template<typename Value_t>
+ inline Value_t fp_log10(const Value_t& x)
+ {
+ return fp_log(x) * fp_const_log10inv<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_trunc(const Value_t& x)
+ {
+ return x < Value_t() ? fp_ceil(x) : fp_floor(x);
+ }
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ 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<typename Value_t>
+ 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<typename Value_t>
+ struct Epsilon
+ {
+ static Value_t value;
+ static Value_t defaultValue() { return 0; }
+ };
+
+ template<> inline double Epsilon<double>::defaultValue() { return 1E-12; }
+ template<> inline float Epsilon<float>::defaultValue() { return 1E-5F; }
+ template<> inline long double Epsilon<long double>::defaultValue() { return 1E-14L; }
+
+ template<> inline std::complex<double>
+ Epsilon<std::complex<double> >::defaultValue() { return 1E-12; }
+
+ template<> inline std::complex<float>
+ Epsilon<std::complex<float> >::defaultValue() { return 1E-5F; }
+
+ template<> inline std::complex<long double>
+ Epsilon<std::complex<long double> >::defaultValue() { return 1E-14L; }
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+ template<> inline MpfrFloat
+ Epsilon<MpfrFloat>::defaultValue() { return MpfrFloat::someEpsilon(); }
+#endif
+
+ template<typename Value_t> Value_t Epsilon<Value_t>::value =
+ Epsilon<Value_t>::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<long>() { 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<typename Value_t>
+ inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); }
+#else
+ template<typename Value_t>
+ 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<typename Value_t> inline Value_t fp_arg(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_exp2(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_int(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_trunc(const Value_t& x);
+ template<typename Value_t>
+ inline void fp_sinCos(Value_t& , Value_t& , const Value_t& );
+ template<typename Value_t>
+ 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<typename T>
+ 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<float>
+ { enum { result = true }; };
+ template<> struct FP_ProbablyHasFastLibcComplex<double>
+ { enum { result = true }; };
+ template<> struct FP_ProbablyHasFastLibcComplex<long double>
+ { enum { result = true }; };
+#endif
+
+ template<typename T>
+ inline const std::complex<T> fp_make_imag(const std::complex<T>& v)
+ {
+ return std::complex<T> ( T(), v.real() );
+ }
+
+ template<typename T>
+ inline std::complex<T> fp_real(const std::complex<T>& x)
+ {
+ return x.real();
+ }
+ template<typename T>
+ inline std::complex<T> fp_imag(const std::complex<T>& x)
+ {
+ return x.imag();
+ }
+ template<typename T>
+ inline std::complex<T> fp_arg(const std::complex<T>& x)
+ {
+ return std::arg(x);
+ }
+ template<typename T>
+ inline std::complex<T> fp_conj(const std::complex<T>& x)
+ {
+ return std::conj(x);
+ }
+ template<typename T, bool>
+ inline std::complex<T> fp_polar(const T& x, const T& y)
+ {
+ T si, co; fp_sinCos(si, co, y);
+ return std::complex<T> (x*co, x*si);
+ }
+ template<typename T>
+ inline std::complex<T> fp_polar(const std::complex<T>& x, const std::complex<T>& y)
+ {
+ // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers
+ return fp_polar<T,true> (x.real(), y.real());
+ //return std::polar(x.real(), y.real());
+ //return x * (fp_cos(y) + (std::complex<T>(0,1) * fp_sin(y));
+ }
+
+ // These provide fallbacks in case there's no library function
+ template<typename T>
+ inline std::complex<T> fp_floor(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_floor(x.real()), fp_floor(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_trunc(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_trunc(x.real()), fp_trunc(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_int(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_int(x.real()), fp_int(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_ceil(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_ceil(x.real()), fp_ceil(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_abs(const std::complex<T>& 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<typename T>
+ inline std::complex<T> fp_exp(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::result)
+ return std::exp(x);
+ return fp_polar<T,true>(fp_exp(x.real()), x.imag());
+ }
+ template<typename T>
+ inline std::complex<T> fp_log(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::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<T>( fp_log(fp_abs(x.real())),
+ fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here!
+ return std::complex<T>(
+ fp_log(std::norm(x)) * T(0.5),
+ fp_arg(x).real() );
+ }
+ template<typename T>
+ inline std::complex<T> fp_sqrt(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::result)
+ return std::sqrt(x);
+ return fp_polar<T,true> (fp_sqrt(fp_abs(x).real()),
+ T(0.5)*fp_arg(x).real());
+ }
+ template<typename T>
+ inline std::complex<T> fp_acos(const std::complex<T>& x)
+ {
+ // -i * log(x + i * sqrt(1 - x^2))
+ const std::complex<T> 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<typename T>
+ inline std::complex<T> fp_asin(const std::complex<T>& x)
+ {
+ // -i * log(i*x + sqrt(1 - x^2))
+ const std::complex<T> 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<typename T>
+ inline std::complex<T> fp_atan(const std::complex<T>& x)
+ {
+ // 0.5i * (log(1-i*x) - log(1+i*x))
+ // -0.5i * log( (1+i*x) / (1-i*x) )
+ const std::complex<T> 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<typename T>
+ inline std::complex<T> fp_cos(const std::complex<T>& x)
+ {
+ return std::cos(x);
+ // // (exp(i*x) + exp(-i*x)) / (2)
+ // //const std::complex<T> 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<T> (
+ // fp_cos(x.real())*fp_cosh(x.imag()),
+ // -fp_sin(x.real())*fp_sinh(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_sin(const std::complex<T>& x)
+ {
+ return std::sin(x);
+ // // (exp(i*x) - exp(-i*x)) / (2i)
+ // //const std::complex<T> 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<T> (
+ // fp_sin(x.real())*fp_cosh(x.imag()),
+ // fp_cos(x.real())*fp_sinh(x.imag()));
+ }
+ template<typename T>
+ inline void fp_sinCos(
+ std::complex<T>& sinvalue,
+ std::complex<T>& cosvalue,
+ const std::complex<T>& x)
+ {
+ //const std::complex<T> 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<T>(srx*cix, crx*six);
+ cosvalue = std::complex<T>(crx*cix, -srx*six);
+ }
+ template<typename T>
+ inline void fp_sinhCosh(
+ std::complex<T>& sinhvalue,
+ std::complex<T>& coshvalue,
+ const std::complex<T>& x)
+ {
+ T srx, crx; fp_sinhCosh(srx, crx, x.real());
+ T six, cix; fp_sinCos(six, cix, x.imag());
+ sinhvalue = std::complex<T>(srx*cix, crx*six);
+ coshvalue = std::complex<T>(crx*cix, srx*six);
+ }
+ template<typename T>
+ inline std::complex<T> fp_tan(const std::complex<T>& x)
+ {
+ return std::tan(x);
+ //std::complex<T> si, co;
+ //fp_sinCos(si, co, x);
+ //return si/co;
+ // // (i-i*exp(2i*x)) / (exp(2i*x)+1)
+ // const std::complex<T> 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<typename T>
+ inline std::complex<T> fp_cosh(const std::complex<T>& x)
+ {
+ return std::cosh(x);
+ // // (exp(x) + exp(-x)) * 0.5
+ // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi)
+ // return std::complex<T> (
+ // fp_cosh(x.real())*fp_cos(x.imag()),
+ // fp_sinh(x.real())*fp_sin(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_sinh(const std::complex<T>& x)
+ {
+ return std::sinh(x);
+ // // (exp(x) - exp(-x)) * 0.5
+ // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi)
+ // return std::complex<T> (
+ // fp_sinh(x.real())*fp_cos(x.imag()),
+ // fp_cosh(x.real())*fp_sin(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_tanh(const std::complex<T>& x)
+ {
+ return std::tanh(x);
+ //std::complex<T> 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<T> exp2x=fp_exp(x+x);
+ // return (exp2x-T(1)) / (exp2x+T(1));
+ }
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename T>
+ inline std::complex<T> fp_acosh(const std::complex<T>& x)
+ { return fp_log(x + fp_sqrt(x*x - std::complex<T>(1))); }
+ template<typename T>
+ inline std::complex<T> fp_asinh(const std::complex<T>& x)
+ { return fp_log(x + fp_sqrt(x*x + std::complex<T>(1))); }
+ template<typename T>
+ inline std::complex<T> fp_atanh(const std::complex<T>& x)
+ { return fp_log( (std::complex<T>(1)+x) / (std::complex<T>(1)-x))
+ * std::complex<T>(0.5); }
+#endif
+ template<typename T>
+ inline std::complex<T> fp_pow(const std::complex<T>& x, const std::complex<T>& 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> t =
+ (x.imag() != T())
+ ? fp_log(x)
+ : std::complex<T> (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<T,true> (fp_exp(y.real()*t.real()), y.real()*t.imag());
+ }
+ template<typename T>
+ inline std::complex<T> fp_cbrt(const std::complex<T>& 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> t(fp_log(x));
+ return fp_polar<T,true> (fp_exp(t.real() / T(3)), t.imag() / T(3));
+ }
+
+ template<typename T>
+ inline std::complex<T> fp_exp2(const std::complex<T>& x)
+ {
+ // pow(2, x)
+ // polar(2^Xr, Xi*log(2))
+ return fp_polar<T,true> (fp_exp2(x.real()), x.imag()*fp_const_log2<T>());
+ }
+ template<typename T>
+ inline std::complex<T> fp_mod(const std::complex<T>& x, const std::complex<T>& 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<T> 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<typename T>
+ inline std::ostream& operator<<(std::ostream& os, const std::complex<T>& 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<typename T>
+ inline T fp_complexScalarize(const std::complex<T>& x)
+ {
+ T res(std::norm(x));
+ if(x.real() < T()) res = -res;
+ return res;
+ }
+ template<typename T>
+ 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<typename T> \
+ inline bool operator op (const std::complex<T>& x, T y) \
+ { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \
+ template<typename T> \
+ inline bool operator op (const std::complex<T>& x, const std::complex<T>& y) \
+ { return fp_complexScalarize(x) op \
+ fp_complexScalarize(y); } \
+ template<typename T> \
+ inline bool operator op (T x, const std::complex<T>& y) \
+ { return fp_realComplexScalarize(x) op fp_complexScalarize(y); }
+ d( < ) d( <= ) d( > ) d( >= )
+ #undef d
+#endif
+
+ template<typename Value_t>
+ inline Value_t fp_real(const Value_t& x) { return x; }
+ template<typename Value_t>
+ inline Value_t fp_imag(const Value_t& ) { return Value_t(); }
+ template<typename Value_t>
+ inline Value_t fp_arg(const Value_t& x)
+ { return x < Value_t() ? -fp_const_pi<Value_t>() : Value_t(); }
+ template<typename Value_t>
+ inline Value_t fp_conj(const Value_t& x) { return x; }
+ template<typename Value_t>
+ 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<typename Value_t>
+ inline std::complex<Value_t> fp_atan2(const std::complex<Value_t>& y,
+ const std::complex<Value_t>& x)
+ {
+ if(y == Value_t()) return fp_arg(x);
+ if(x == Value_t()) return fp_const_pi<Value_t>() * Value_t(-0.5);
+ // 2*atan(y / (sqrt(x^2+y^2) + x) )
+ // 2*atan( (sqrt(x^2+y^2) - x) / y)
+ std::complex<Value_t> res( fp_atan(y / (fp_hypot(x,y) + x)) );
+ return res+res;
+ }
+
+// -------------------------------------------------------------------------
+// Comparison
+// -------------------------------------------------------------------------
+ template<typename Value_t>
+ inline bool fp_equal(const Value_t& x, const Value_t& y)
+ { return IsIntType<Value_t>::result
+ ? (x == y)
+ : (fp_abs(x - y) <= Epsilon<Value_t>::value); }
+
+ template<typename Value_t>
+ inline bool fp_nequal(const Value_t& x, const Value_t& y)
+ { return IsIntType<Value_t>::result
+ ? (x != y)
+ : (fp_abs(x - y) > Epsilon<Value_t>::value); }
+
+ template<typename Value_t>
+ inline bool fp_less(const Value_t& x, const Value_t& y)
+ { return IsIntType<Value_t>::result
+ ? (x < y)
+ : (x < y - Epsilon<Value_t>::value); }
+
+ template<typename Value_t>
+ inline bool fp_lessOrEq(const Value_t& x, const Value_t& y)
+ { return IsIntType<Value_t>::result
+ ? (x <= y)
+ : (x <= y + Epsilon<Value_t>::value); }
+
+
+ template<typename Value_t>
+ inline bool fp_greater(const Value_t& x, const Value_t& y)
+ { return fp_less(y, x); }
+
+ template<typename Value_t>
+ inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y)
+ { return fp_lessOrEq(y, x); }
+
+ template<typename Value_t>
+ inline bool fp_truth(const Value_t& d)
+ {
+ return IsIntType<Value_t>::result
+ ? d != Value_t()
+ : fp_abs(d) >= Value_t(0.5);
+ }
+
+ template<typename Value_t>
+ inline bool fp_absTruth(const Value_t& abs_d)
+ {
+ return IsIntType<Value_t>::result
+ ? abs_d > Value_t()
+ : abs_d >= Value_t(0.5);
+ }
+
+ template<typename Value_t>
+ inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2)
+ { return d1<d2 ? d1 : d2; }
+
+ template<typename Value_t>
+ inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2)
+ { return d1>d2 ? d1 : d2; }
+
+ template<typename Value_t>
+ inline const Value_t fp_not(const Value_t& b)
+ { return Value_t(!fp_truth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_notNot(const Value_t& b)
+ { return Value_t(fp_truth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_absNot(const Value_t& b)
+ { return Value_t(!fp_absTruth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_absNotNot(const Value_t& b)
+ { return Value_t(fp_absTruth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_and(const Value_t& a, const Value_t& b)
+ { return Value_t(fp_truth(a) && fp_truth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_or(const Value_t& a, const Value_t& b)
+ { return Value_t(fp_truth(a) || fp_truth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b)
+ { return Value_t(fp_absTruth(a) && fp_absTruth(b)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_absOr(const Value_t& a, const Value_t& b)
+ { return Value_t(fp_absTruth(a) || fp_absTruth(b)); }
+
+ template<typename Value_t>
+ 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 ComplexType>
+ bool HasInvalidRangesOpcode(unsigned op);
+
+ template<typename Value_t>
+ inline Value_t DegreesToRadians(const Value_t& degrees)
+ {
+ return degrees * fp_const_deg_to_rad<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline Value_t RadiansToDegrees(const Value_t& radians)
+ {
+ return radians * fp_const_rad_to_deg<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline long makeLongInteger(const Value_t& value)
+ {
+ return (long) fp_int(value);
+ }
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ template<typename T>
+ inline long makeLongInteger(const std::complex<T>& value)
+ {
+ return (long) fp_int( std::abs(value) );
+ }
+#endif
+
+ // Is value an integer that fits in "long" datatype?
+ template<typename Value_t>
+ inline bool isLongInteger(const Value_t& value)
+ {
+ return value == Value_t( makeLongInteger(value) );
+ }
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ inline bool isEvenInteger(const Value_t& value)
+ {
+ const Value_t halfValue = value * Value_t(0.5);
+ return fp_equal(halfValue, fp_floor(halfValue));
+ }
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y)
+ {
+ return fp_exp(fp_log(x) * y);
+ }
+
+ template<typename Value_t>
+ 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<typename Value_t>
+ 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<typename Value_t>
+ 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_