diff --git a/include/boost/math/bindings/rr.hpp b/include/boost/math/bindings/rr.hpp new file mode 100644 index 000000000..3708b068f --- /dev/null +++ b/include/boost/math/bindings/rr.hpp @@ -0,0 +1,707 @@ +// Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef BOOST_MATH_NTL_RR_HPP +#define BOOST_MATH_NTL_RR_HPP + +namespace boost{ namespace math{ + +namespace ntl +{ + +class RR; + +RR ldexp(RR r, int exp); +RR frexp(RR r, int* exp); + +class RR +{ +public: + // Constructors: + RR() {} + RR(const ::NTL::RR& c) : m_value(c){} + RR(char c) + { + m_value = c; + } +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + RR(wchar_t c) + { + m_value = c; + } +#endif + RR(unsigned char c) + { + m_value = c; + } + RR(signed char c) + { + m_value = c; + } + RR(unsigned short c) + { + m_value = c; + } + RR(short c) + { + m_value = c; + } + RR(unsigned int c) + { + assign_large_int(c); + } + RR(int c) + { + assign_large_int(c); + } + RR(unsigned long c) + { + assign_large_int(c); + } + RR(long c) + { + assign_large_int(c); + } +#ifdef BOOST_HAS_LONG_LONG + RR(unsigned long long c) + { + assign_large_int(c); + } + RR(long long c) + { + assign_large_int(c); + } +#endif + RR(float c) + { + m_value = c; + } + RR(double c) + { + m_value = c; + } + RR(long double c) + { + assign_large_real(c); + } + + // Assignment: + RR& operator=(char c) { m_value = c; return *this; } + RR& operator=(unsigned char c) { m_value = c; return *this; } + RR& operator=(signed char c) { m_value = c; return *this; } +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + RR& operator=(wchar_t c) { m_value = c; return *this; } +#endif + RR& operator=(short c) { m_value = c; return *this; } + RR& operator=(unsigned short c) { m_value = c; return *this; } + RR& operator=(int c) { assign_large_int(c); return *this; } + RR& operator=(unsigned int c) { assign_large_int(c); return *this; } + RR& operator=(long c) { assign_large_int(c); return *this; } + RR& operator=(unsigned long c) { assign_large_int(c); return *this; } +#ifdef BOOST_HAS_LONG_LONG + RR& operator=(long long c) { assign_large_int(c); return *this; } + RR& operator=(unsigned long long c) { assign_large_int(c); return *this; } +#endif + RR& operator=(float c) { m_value = c; return *this; } + RR& operator=(double c) { m_value = c; return *this; } + RR& operator=(long double c) { assign_large_real(c); return *this; } + + // Access: + NTL::RR& value(){ return m_value; } + NTL::RR const& value()const{ return m_value; } + + // Member arithmetic: + RR& operator+=(const RR& other) + { m_value += other.value(); return *this; } + RR& operator-=(const RR& other) + { m_value -= other.value(); return *this; } + RR& operator*=(const RR& other) + { m_value *= other.value(); return *this; } + RR& operator/=(const RR& other) + { m_value /= other.value(); return *this; } + RR operator-()const + { return -m_value; } + RR const& operator+()const + { return *this; } + + // RR compatibity: + const ::NTL::ZZ& mantissa() const + { return m_value.mantissa(); } + long exponent() const + { return m_value.exponent(); } + + static void SetPrecision(long p) + { ::NTL::RR::SetPrecision(p); } + + static long precision() + { return ::NTL::RR::precision(); } + + static void SetOutputPrecision(long p) + { ::NTL::RR::SetOutputPrecision(p); } + static long OutputPrecision() + { return ::NTL::RR::OutputPrecision(); } + + +private: + ::NTL::RR m_value; + + template + void assign_large_real(const V& a) + { + using std::frexp; + using std::ldexp; + using std::floor; + if (a == 0) { + clear(m_value); + return; + } + + if (a == 1) { + NTL::set(m_value); + return; + } + + if (!(boost::math::isfinite)(a)) + { + throw std::overflow_error("Cannot construct an instance of NTL::RR with an infinite value."); + } + + int e; + long double f, term; + ::NTL::RR t; + clear(m_value); + + f = frexp(a, &e); + + while(f) + { + // extract 30 bits from f: + f = ldexp(f, 30); + term = floor(f); + e -= 30; + conv(t.x, (int)term); + t.e = e; + m_value += t; + f -= term; + } + } + + template + void assign_large_int(V a) + { +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4146) +#endif + clear(m_value); + int exp = 0; + NTL::RR t; + bool neg = a < V(0) ? true : false; + if(neg) + a = -a; + while(a) + { + t = static_cast(a & 0xffff); + m_value += ldexp(RR(t), exp).value(); + a >>= 16; + exp += 16; + } + if(neg) + m_value = -m_value; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + } +}; + +// Non-member arithmetic: +inline RR operator+(const RR& a, const RR& b) +{ + RR result(a); + result += b; + return result; +} +inline RR operator-(const RR& a, const RR& b) +{ + RR result(a); + result -= b; + return result; +} +inline RR operator*(const RR& a, const RR& b) +{ + RR result(a); + result *= b; + return result; +} +inline RR operator/(const RR& a, const RR& b) +{ + RR result(a); + result /= b; + return result; +} + +// Comparison: +inline bool operator == (const RR& a, const RR& b) +{ return a.value() == b.value() ? true : false; } +inline bool operator != (const RR& a, const RR& b) +{ return a.value() != b.value() ? true : false;} +inline bool operator < (const RR& a, const RR& b) +{ return a.value() < b.value() ? true : false; } +inline bool operator <= (const RR& a, const RR& b) +{ return a.value() <= b.value() ? true : false; } +inline bool operator > (const RR& a, const RR& b) +{ return a.value() > b.value() ? true : false; } +inline bool operator >= (const RR& a, const RR& b) +{ return a.value() >= b.value() ? true : false; } + +#if 0 +// Non-member mixed compare: +template +inline bool operator == (const T& a, const RR& b) +{ + return a == b.value(); +} +template +inline bool operator != (const T& a, const RR& b) +{ + return a != b.value(); +} +template +inline bool operator < (const T& a, const RR& b) +{ + return a < b.value(); +} +template +inline bool operator > (const T& a, const RR& b) +{ + return a > b.value(); +} +template +inline bool operator <= (const T& a, const RR& b) +{ + return a <= b.value(); +} +template +inline bool operator >= (const T& a, const RR& b) +{ + return a >= b.value(); +} +#endif // Non-member mixed compare: + +// Non-member functions: +/* +inline RR acos(RR a) +{ return ::NTL::acos(a.value()); } +*/ +inline RR cos(RR a) +{ return ::NTL::cos(a.value()); } +/* +inline RR asin(RR a) +{ return ::NTL::asin(a.value()); } +inline RR atan(RR a) +{ return ::NTL::atan(a.value()); } +inline RR atan2(RR a, RR b) +{ return ::NTL::atan2(a.value(), b.value()); } +*/ +inline RR ceil(RR a) +{ return ::NTL::ceil(a.value()); } +/* +inline RR fmod(RR a, RR b) +{ return ::NTL::fmod(a.value(), b.value()); } +inline RR cosh(RR a) +{ return ::NTL::cosh(a.value()); } +*/ +inline RR exp(RR a) +{ return ::NTL::exp(a.value()); } +inline RR fabs(RR a) +{ return ::NTL::fabs(a.value()); } +inline RR abs(RR a) +{ return ::NTL::abs(a.value()); } +inline RR floor(RR a) +{ return ::NTL::floor(a.value()); } +/* +inline RR modf(RR a, RR* ipart) +{ + ::NTL::RR ip; + RR result = modf(a.value(), &ip); + *ipart = ip; + return result; +} +inline RR frexp(RR a, int* expon) +{ return ::NTL::frexp(a.value(), expon); } +inline RR ldexp(RR a, int expon) +{ return ::NTL::ldexp(a.value(), expon); } +*/ +inline RR log(RR a) +{ return ::NTL::log(a.value()); } +inline RR log10(RR a) +{ return ::NTL::log10(a.value()); } +/* +inline RR tan(RR a) +{ return ::NTL::tan(a.value()); } +*/ +inline RR pow(RR a, RR b) +{ return ::NTL::pow(a.value(), b.value()); } +inline RR pow(RR a, int b) +{ return ::NTL::power(a.value(), b); } +inline RR sin(RR a) +{ return ::NTL::sin(a.value()); } +/* +inline RR sinh(RR a) +{ return ::NTL::sinh(a.value()); } +*/ +inline RR sqrt(RR a) +{ return ::NTL::sqrt(a.value()); } +/* +inline RR tanh(RR a) +{ return ::NTL::tanh(a.value()); } +*/ + inline RR pow(const RR& r, long l) + { + return ::NTL::power(r.value(), l); + } + inline RR tan(const RR& a) + { + return sin(a)/cos(a); + } + inline RR frexp(RR r, int* exp) + { + *exp = r.value().e; + r.value().e = 0; + while(r >= 1) + { + *exp += 1; + r.value().e -= 1; + } + while(r < 0.5) + { + *exp -= 1; + r.value().e += 1; + } + BOOST_ASSERT(r < 1); + BOOST_ASSERT(r >= 0.5); + return r; + } + inline RR ldexp(RR r, int exp) + { + r.value().e += exp; + return r; + } + +// Streaming: +template +inline std::basic_ostream& operator<<(std::basic_ostream& os, const RR& a) +{ + return os << a.value(); +} +template +inline std::basic_istream& operator>>(std::basic_istream& is, RR& a) +{ + ::NTL::RR v; + is >> v; + a = v; + return is; +} + +} // namespace ntl + +namespace tools +{ + +template<> +inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + return ::NTL::RR::precision(); +} + +template <> +inline float real_cast(boost::math::ntl::RR t) +{ + double r; + conv(r, t.value()); + return static_cast(r); +} +template <> +inline double real_cast(boost::math::ntl::RR t) +{ + double r; + conv(r, t.value()); + return r; +} + +namespace detail{ + +template +void convert_to_long_result(NTL::RR const& r, I& result) +{ + result = 0; + I last_result(0); + NTL::RR t(r); + double term; + do + { + conv(term, t); + last_result = result; + result += static_cast(term); + t -= term; + }while(result != last_result); +} + +} + +template <> +inline long double real_cast(boost::math::ntl::RR t) +{ + long double result(0); + detail::convert_to_long_result(t.value(), result); + return result; +} +template <> +inline boost::math::ntl::RR real_cast(boost::math::ntl::RR t) +{ + return t; +} +template <> +inline unsigned real_cast(boost::math::ntl::RR t) +{ + unsigned result; + detail::convert_to_long_result(t.value(), result); + return result; +} +template <> +inline int real_cast(boost::math::ntl::RR t) +{ + unsigned result; + detail::convert_to_long_result(t.value(), result); + return result; +} + +template <> +inline boost::math::ntl::RR max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + static bool has_init = false; + static NTL::RR val; + if(!has_init) + { + val = 1; + val.e = NTL_OVFBND-20; + has_init = true; + } + return val; +} + +template <> +inline boost::math::ntl::RR min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + static bool has_init = false; + static NTL::RR val; + if(!has_init) + { + val = 1; + val.e = -NTL_OVFBND+20; + has_init = true; + } + return val; +} + +template <> +inline boost::math::ntl::RR log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + static bool has_init = false; + static NTL::RR val; + if(!has_init) + { + val = 1; + val.e = NTL_OVFBND-20; + val = log(val); + has_init = true; + } + return val; +} + +template <> +inline boost::math::ntl::RR log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + static bool has_init = false; + static NTL::RR val; + if(!has_init) + { + val = 1; + val.e = -NTL_OVFBND+20; + val = log(val); + has_init = true; + } + return val; +} + +template <> +inline boost::math::ntl::RR epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + return ldexp(boost::math::ntl::RR(1), 1-boost::math::policies::digits >()); +} + +} // namespace tools + +// +// The number of digits precision in RR can vary with each call +// so we need to recalculate these with each call: +// +namespace constants{ + +template<> inline boost::math::ntl::RR pi(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + NTL::RR result; + ComputePi(result); + return result; +} +template<> inline boost::math::ntl::RR e(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR)) +{ + NTL::RR result; + result = 1; + return exp(result); +} + +} // namespace constants + +namespace ntl{ + // + // These are some fairly brain-dead versions of the math + // functions that NTL fails to provide. + // + + + // + // Inverse trig functions: + // + struct asin_root + { + asin_root(RR const& target) : t(target){} + + std::tr1::tuple operator()(RR const& p) + { + RR f0 = sin(p); + RR f1 = cos(p); + RR f2 = -f0; + f0 -= t; + return std::tr1::make_tuple(f0, f1, f2); + } + private: + RR t; + }; + + inline RR asin(RR z) + { + double r; + conv(r, z.value()); + return boost::math::tools::halley_iterate( + asin_root(z), + RR(std::asin(r)), + RR(-boost::math::constants::pi()/2), + RR(boost::math::constants::pi()/2), + NTL::RR::precision()); + } + + struct acos_root + { + acos_root(RR const& target) : t(target){} + + std::tr1::tuple operator()(RR const& p) + { + RR f0 = cos(p); + RR f1 = -sin(p); + RR f2 = -f0; + f0 -= t; + return std::tr1::make_tuple(f0, f1, f2); + } + private: + RR t; + }; + + inline RR acos(RR z) + { + double r; + conv(r, z.value()); + return boost::math::tools::halley_iterate( + acos_root(z), + RR(std::acos(r)), + RR(-boost::math::constants::pi()/2), + RR(boost::math::constants::pi()/2), + NTL::RR::precision()); + } + + struct atan_root + { + atan_root(RR const& target) : t(target){} + + std::tr1::tuple operator()(RR const& p) + { + RR c = cos(p); + RR ta = tan(p); + RR f0 = ta - t; + RR f1 = 1 / (c * c); + RR f2 = 2 * ta / (c * c); + return std::tr1::make_tuple(f0, f1, f2); + } + private: + RR t; + }; + + inline RR atan(RR z) + { + double r; + conv(r, z.value()); + return boost::math::tools::halley_iterate( + atan_root(z), + RR(std::atan(r)), + -boost::math::constants::pi()/2, + boost::math::constants::pi()/2, + NTL::RR::precision()); + } + + inline RR sinh(RR z) + { + return (expm1(z.value()) - expm1(-z.value())) / 2; + } + + inline RR cosh(RR z) + { + return (exp(z) + exp(-z)) / 2; + } + + inline RR tanh(RR z) + { + return sinh(z) / cosh(z); + } + + inline RR fmod(RR x, RR y) + { + // This is a really crummy version of fmod, we rely on lots + // of digits to get us out of trouble... + RR factor = floor(x/y); + return x - factor * y; + } + +} // namespace ntl + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_REAL_CONCEPT_HPP + + diff --git a/include/boost/math/common_factor_rt.hpp b/include/boost/math/common_factor_rt.hpp index 5b8cd45ea..6200b96a6 100644 --- a/include/boost/math/common_factor_rt.hpp +++ b/include/boost/math/common_factor_rt.hpp @@ -15,6 +15,7 @@ #include // for BOOST_NESTED_TEMPLATE, etc. #include // for std::numeric_limits +#include namespace boost @@ -114,6 +115,69 @@ namespace detail return ( result < zero ) ? -result : result; } + // Greatest common divisor for unsigned binary integers + template < typename BuiltInUnsigned > + BuiltInUnsigned + gcd_binary + ( + BuiltInUnsigned u, + BuiltInUnsigned v + ) + { + if ( u && v ) + { + // Shift out common factors of 2 + unsigned shifts = 0; + + while ( !(u & 1u) && !(v & 1u) ) + { + ++shifts; + u >>= 1; + v >>= 1; + } + + // Start with the still-even one, if any + BuiltInUnsigned r[] = { u, v }; + unsigned which = static_cast( u & 1u ); + + // Whittle down the values via their differences + do + { +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + while ( !(r[ which ] & 1u) ) + { + r[ which ] = (r[which] >> 1); + } +#else + // Remove factors of two from the even one + while ( !(r[ which ] & 1u) ) + { + r[ which ] >>= 1; + } +#endif + + // Replace the larger of the two with their difference + if ( r[!which] > r[which] ) + { + which ^= 1u; + } + + r[ which ] -= r[ !which ]; + } + while ( r[which] ); + + // Shift-in the common factor of 2 to the residues' GCD + return r[ !which ] << shifts; + } + else + { + // At least one input is zero, return the other + // (adding since zero is the additive identity) + // or zero if both are zero. + return u + v; + } + } + // Least common multiple for rings (including unsigned integers) template < typename RingType > inline @@ -228,6 +292,46 @@ namespace detail }; #endif + // Specialize for the built-in integers +#define BOOST_PRIVATE_GCD_UF( Ut ) \ + template < > struct gcd_optimal_evaluator \ + { Ut operator ()( Ut a, Ut b ) const { return gcd_binary( a, b ); } } + + BOOST_PRIVATE_GCD_UF( unsigned char ); + BOOST_PRIVATE_GCD_UF( unsigned short ); + BOOST_PRIVATE_GCD_UF( unsigned ); + BOOST_PRIVATE_GCD_UF( unsigned long ); + +#ifdef BOOST_HAS_LONG_LONG + BOOST_PRIVATE_GCD_UF( unsigned long long ); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_PRIVATE_GCD_UF( unsigned __int64 ); +#endif + +#undef BOOST_PRIVATE_GCD_UF + +#define BOOST_PRIVATE_GCD_SF( St, Ut ) \ + template < > struct gcd_optimal_evaluator \ + { St operator ()( St a, St b ) const { Ut const a_abs = \ + static_cast( a < 0 ? -a : +a ), b_abs = static_cast( \ + b < 0 ? -b : +b ); return static_cast( \ + gcd_optimal_evaluator()(a_abs, b_abs) ); } } + + BOOST_PRIVATE_GCD_SF( signed char, unsigned char ); + BOOST_PRIVATE_GCD_SF( short, unsigned short ); + BOOST_PRIVATE_GCD_SF( int, unsigned ); + BOOST_PRIVATE_GCD_SF( long, unsigned long ); + + BOOST_PRIVATE_GCD_SF( char, unsigned char ); // should work even if unsigned + +#ifdef BOOST_HAS_LONG_LONG + BOOST_PRIVATE_GCD_SF( long long, unsigned long long ); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_PRIVATE_GCD_SF( __int64, unsigned __int64 ); +#endif + +#undef BOOST_PRIVATE_GCD_SF + #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template < typename T, bool IsSpecialized, bool IsSigned > diff --git a/include/boost/math/complex/details.hpp b/include/boost/math/complex/details.hpp index 410625407..889c79ef3 100644 --- a/include/boost/math/complex/details.hpp +++ b/include/boost/math/complex/details.hpp @@ -10,8 +10,8 @@ // inverse trig complex functions, it also contains all the includes // that we need to implement all these functions. // -#include #include +#include #include #include #include // isnan where available diff --git a/include/boost/math/concepts/distributions.hpp b/include/boost/math/concepts/distributions.hpp new file mode 100644 index 000000000..3773cf050 --- /dev/null +++ b/include/boost/math/concepts/distributions.hpp @@ -0,0 +1,204 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// distributions.hpp provides definitions of the concept of a distribution +// and non-member accessor functions that must be implemented by all distributions. +// This is used to verify that +// all the features of a distributions have been fully implemented. + +#ifndef BOOST_MATH_DISTRIBUTION_CONCEPT_HPP +#define BOOST_MATH_DISTRIBUTION_CONCEPT_HPP + +#include +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4100) +#pragma warning(disable: 4510) +#pragma warning(disable: 4610) +#endif +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +#include + +namespace boost{ +namespace math{ + +namespace concepts +{ +// Begin by defining a concept archetype +// for a distribution class: +// +template +class distribution_archetype +{ +public: + typedef RealType value_type; + + distribution_archetype(const distribution_archetype&); // Copy constructible. + distribution_archetype& operator=(const distribution_archetype&); // Assignable. + + // There is no default constructor, + // but we need a way to instantiate the archetype: + static distribution_archetype& get_object() + { + // will never get caled: + return *reinterpret_cast(0); + } +}; // template class distribution_archetype + +// Non-member accessor functions: +// (This list defines the functions that must be implemented by all distributions). + +template +RealType pdf(const distribution_archetype& dist, const RealType& x); + +template +RealType cdf(const distribution_archetype& dist, const RealType& x); + +template +RealType quantile(const distribution_archetype& dist, const RealType& p); + +template +RealType cdf(const complemented2_type, RealType>& c); + +template +RealType quantile(const complemented2_type, RealType>& c); + +template +RealType mean(const distribution_archetype& dist); + +template +RealType standard_deviation(const distribution_archetype& dist); + +template +RealType variance(const distribution_archetype& dist); + +template +RealType hazard(const distribution_archetype& dist); + +template +RealType chf(const distribution_archetype& dist); +// http://en.wikipedia.org/wiki/Characteristic_function_%28probability_theory%29 + +template +RealType coefficient_of_variation(const distribution_archetype& dist); + +template +RealType mode(const distribution_archetype& dist); + +template +RealType skewness(const distribution_archetype& dist); + +template +RealType kurtosis_excess(const distribution_archetype& dist); + +template +RealType kurtosis(const distribution_archetype& dist); + +template +RealType median(const distribution_archetype& dist); + +template +std::pair range(const distribution_archetype& dist); + +template +std::pair support(const distribution_archetype& dist); + +// +// Next comes the concept checks for verifying that a class +// fullfils the requirements of a Distribution: +// +template +struct DistributionConcept +{ + void constraints() + { + function_requires >(); + function_requires >(); + + typedef typename Distribution::value_type value_type; + + const Distribution& dist = DistributionConcept::get_object(); + + value_type x = 0; + // The result values are ignored in all these checks. + value_type v = cdf(dist, x); + v = cdf(complement(dist, x)); + v = pdf(dist, x); + v = quantile(dist, x); + v = quantile(complement(dist, x)); + v = mean(dist); + v = mode(dist); + v = standard_deviation(dist); + v = variance(dist); + v = hazard(dist, x); + v = chf(dist, x); + v = coefficient_of_variation(dist); + v = skewness(dist); + v = kurtosis(dist); + v = kurtosis_excess(dist); + v = median(dist); + std::pair pv; + pv = range(dist); + pv = support(dist); + + float f = 1; + v = cdf(dist, f); + v = cdf(complement(dist, f)); + v = pdf(dist, f); + v = quantile(dist, f); + v = quantile(complement(dist, f)); + v = hazard(dist, f); + v = chf(dist, f); + double d = 1; + v = cdf(dist, d); + v = cdf(complement(dist, d)); + v = pdf(dist, d); + v = quantile(dist, d); + v = quantile(complement(dist, d)); + v = hazard(dist, d); + v = chf(dist, d); + long double ld = 1; + v = cdf(dist, ld); + v = cdf(complement(dist, ld)); + v = pdf(dist, ld); + v = quantile(dist, ld); + v = quantile(complement(dist, ld)); + v = hazard(dist, ld); + v = chf(dist, ld); + int i = 1; + v = cdf(dist, i); + v = cdf(complement(dist, i)); + v = pdf(dist, i); + v = quantile(dist, i); + v = quantile(complement(dist, i)); + v = hazard(dist, i); + v = chf(dist, i); + unsigned long li = 1; + v = cdf(dist, li); + v = cdf(complement(dist, li)); + v = pdf(dist, li); + v = quantile(dist, li); + v = quantile(complement(dist, li)); + v = hazard(dist, li); + v = chf(dist, li); + } +private: + static Distribution& get_object() + { + // will never get called: + static char buf[sizeof(Distribution)]; + return * reinterpret_cast(buf); + } +}; // struct DistributionConcept + +} // namespace concepts +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_DISTRIBUTION_CONCEPT_HPP + diff --git a/include/boost/math/concepts/real_concept.hpp b/include/boost/math/concepts/real_concept.hpp new file mode 100644 index 000000000..d79268ed7 --- /dev/null +++ b/include/boost/math/concepts/real_concept.hpp @@ -0,0 +1,388 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Test real concept. + +// real_concept is an archetype for User defined Real types. + +// This file defines the features, constructors, operators, functions... +// that are essential to use mathematical and statistical functions. +// The template typename "RealType" is used where this type +// (as well as the normal built-in types, float, double & long double) +// can be used. +// That this is the minimum set is confirmed by use as a type +// in tests of all functions & distributions, for example: +// test_spots(0.F); & test_spots(0.); for float and double, but also +// test_spots(boost::math::concepts::real_concept(0.)); +// NTL quad_float type is an example of a type meeting the requirements, +// but note minor additions are needed - see ntl.diff and documentation +// "Using With NTL - a High-Precision Floating-Point Library". + +#include +#include +#include +#include +#include +#include +#include +#include +#include // fmodl + +#ifndef BOOST_MATH_REAL_CONCEPT_HPP +#define BOOST_MATH_REAL_CONCEPT_HPP + +namespace boost{ namespace math{ + +namespace concepts +{ + +class real_concept +{ +public: + // Constructors: + real_concept() : m_value(0){} + real_concept(char c) : m_value(c){} +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + real_concept(wchar_t c) : m_value(c){} +#endif + real_concept(unsigned char c) : m_value(c){} + real_concept(signed char c) : m_value(c){} + real_concept(unsigned short c) : m_value(c){} + real_concept(short c) : m_value(c){} + real_concept(unsigned int c) : m_value(c){} + real_concept(int c) : m_value(c){} + real_concept(unsigned long c) : m_value(c){} + real_concept(long c) : m_value(c){} +#if defined(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC) + real_concept(unsigned long long c) : m_value(static_cast(c)){} + real_concept(long long c) : m_value(static_cast(c)){} +#elif defined(BOOST_HAS_MS_INT64) + real_concept(unsigned __int64 c) : m_value(static_cast(c)){} + real_concept(__int64 c) : m_value(static_cast(c)){} +#endif + real_concept(float c) : m_value(c){} + real_concept(double c) : m_value(c){} + real_concept(long double c) : m_value(c){} + + // Assignment: + real_concept& operator=(char c) { m_value = c; return *this; } + real_concept& operator=(unsigned char c) { m_value = c; return *this; } + real_concept& operator=(signed char c) { m_value = c; return *this; } +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + real_concept& operator=(wchar_t c) { m_value = c; return *this; } +#endif + real_concept& operator=(short c) { m_value = c; return *this; } + real_concept& operator=(unsigned short c) { m_value = c; return *this; } + real_concept& operator=(int c) { m_value = c; return *this; } + real_concept& operator=(unsigned int c) { m_value = c; return *this; } + real_concept& operator=(long c) { m_value = c; return *this; } + real_concept& operator=(unsigned long c) { m_value = c; return *this; } +#ifdef BOOST_HAS_LONG_LONG + real_concept& operator=(long long c) { m_value = static_cast(c); return *this; } + real_concept& operator=(unsigned long long c) { m_value = static_cast(c); return *this; } +#endif + real_concept& operator=(float c) { m_value = c; return *this; } + real_concept& operator=(double c) { m_value = c; return *this; } + real_concept& operator=(long double c) { m_value = c; return *this; } + + // Access: + long double value()const{ return m_value; } + + // Member arithmetic: + real_concept& operator+=(const real_concept& other) + { m_value += other.value(); return *this; } + real_concept& operator-=(const real_concept& other) + { m_value -= other.value(); return *this; } + real_concept& operator*=(const real_concept& other) + { m_value *= other.value(); return *this; } + real_concept& operator/=(const real_concept& other) + { m_value /= other.value(); return *this; } + real_concept operator-()const + { return -m_value; } + real_concept const& operator+()const + { return *this; } + +private: + long double m_value; +}; + +// Non-member arithmetic: +inline real_concept operator+(const real_concept& a, const real_concept& b) +{ + real_concept result(a); + result += b; + return result; +} +inline real_concept operator-(const real_concept& a, const real_concept& b) +{ + real_concept result(a); + result -= b; + return result; +} +inline real_concept operator*(const real_concept& a, const real_concept& b) +{ + real_concept result(a); + result *= b; + return result; +} +inline real_concept operator/(const real_concept& a, const real_concept& b) +{ + real_concept result(a); + result /= b; + return result; +} + +// Comparison: +inline bool operator == (const real_concept& a, const real_concept& b) +{ return a.value() == b.value(); } +inline bool operator != (const real_concept& a, const real_concept& b) +{ return a.value() != b.value();} +inline bool operator < (const real_concept& a, const real_concept& b) +{ return a.value() < b.value(); } +inline bool operator <= (const real_concept& a, const real_concept& b) +{ return a.value() <= b.value(); } +inline bool operator > (const real_concept& a, const real_concept& b) +{ return a.value() > b.value(); } +inline bool operator >= (const real_concept& a, const real_concept& b) +{ return a.value() >= b.value(); } + +#if 0 +// Non-member mixed compare: +template +inline bool operator == (const T& a, const real_concept& b) +{ + return a == b.value(); +} +template +inline bool operator != (const T& a, const real_concept& b) +{ + return a != b.value(); +} +template +inline bool operator < (const T& a, const real_concept& b) +{ + return a < b.value(); +} +template +inline bool operator > (const T& a, const real_concept& b) +{ + return a > b.value(); +} +template +inline bool operator <= (const T& a, const real_concept& b) +{ + return a <= b.value(); +} +template +inline bool operator >= (const T& a, const real_concept& b) +{ + return a >= b.value(); +} +#endif // Non-member mixed compare: + +// Non-member functions: +inline real_concept acos(real_concept a) +{ return std::acos(a.value()); } +inline real_concept cos(real_concept a) +{ return std::cos(a.value()); } +inline real_concept asin(real_concept a) +{ return std::asin(a.value()); } +inline real_concept atan(real_concept a) +{ return std::atan(a.value()); } +inline real_concept atan2(real_concept a, real_concept b) +{ return std::atan2(a.value(), b.value()); } +inline real_concept ceil(real_concept a) +{ return std::ceil(a.value()); } +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#ifdef _WIN32_WCE +// +// Ugly workaround for macro fmodl: +// +inline long double call_fmodl(long double a, long double b) +{ return fmodl(a, b); } +inline real_concept fmod(real_concept a, real_concept b) +{ return call_fmodl(a.value(), b.value()); } +#else +inline real_concept fmod(real_concept a, real_concept b) +{ return fmodl(a.value(), b.value()); } +#endif +#endif +inline real_concept cosh(real_concept a) +{ return std::cosh(a.value()); } +inline real_concept exp(real_concept a) +{ return std::exp(a.value()); } +inline real_concept fabs(real_concept a) +{ return std::fabs(a.value()); } +inline real_concept abs(real_concept a) +{ return std::abs(a.value()); } +inline real_concept floor(real_concept a) +{ return std::floor(a.value()); } +inline real_concept modf(real_concept a, real_concept* ipart) +{ + long double ip; + long double result = std::modf(a.value(), &ip); + *ipart = ip; + return result; +} +inline real_concept frexp(real_concept a, int* expon) +{ return std::frexp(a.value(), expon); } +inline real_concept ldexp(real_concept a, int expon) +{ return std::ldexp(a.value(), expon); } +inline real_concept log(real_concept a) +{ return std::log(a.value()); } +inline real_concept log10(real_concept a) +{ return std::log10(a.value()); } +inline real_concept tan(real_concept a) +{ return std::tan(a.value()); } +inline real_concept pow(real_concept a, real_concept b) +{ return std::pow(a.value(), b.value()); } +#if !defined(__SUNPRO_CC) +inline real_concept pow(real_concept a, int b) +{ return std::pow(a.value(), b); } +#else +inline real_concept pow(real_concept a, int b) +{ return std::pow(a.value(), static_cast(b)); } +#endif +inline real_concept sin(real_concept a) +{ return std::sin(a.value()); } +inline real_concept sinh(real_concept a) +{ return std::sinh(a.value()); } +inline real_concept sqrt(real_concept a) +{ return std::sqrt(a.value()); } +inline real_concept tanh(real_concept a) +{ return std::tanh(a.value()); } + +// Streaming: +template +inline std::basic_ostream& operator<<(std::basic_ostream& os, const real_concept& a) +{ + return os << a.value(); +} +template +inline std::basic_istream& operator>>(std::basic_istream& is, real_concept& a) +{ +#if defined(BOOST_MSVC) && defined(__SGI_STL_PORT) + // + // STLPort 5.1.4 has a problem reading long doubles from strings, + // see http://sourceforge.net/tracker/index.php?func=detail&aid=1811043&group_id=146814&atid=766244 + // + double v; + is >> v; + a = v; + return is; +#elif defined(__SGI_STL_PORT) + std::string s; + long double d; + is >> s; + std::sscanf(s.c_str(), "%Lf", &d); + a = d; + return is; +#else + long double v; + is >> v; + a = v; + return is; +#endif +} + +} // namespace concepts + +namespace tools +{ +// real_cast converts from T to integer and narrower floating-point types. + +// Convert from T to integer types. + +template <> +inline unsigned int real_cast(concepts::real_concept r) +{ + return static_cast(r.value()); +} + +template <> +inline int real_cast(concepts::real_concept r) +{ + return static_cast(r.value()); +} + +template <> +inline long real_cast(concepts::real_concept r) +{ + return static_cast(r.value()); +} + +// Converts from T to narrower floating-point types, float, double & long double. + +template <> +inline float real_cast(concepts::real_concept r) +{ + return static_cast(r.value()); +} +template <> +inline double real_cast(concepts::real_concept r) +{ + return static_cast(r.value()); +} +template <> +inline long double real_cast(concepts::real_concept r) +{ + return r.value(); +} + +template <> +inline concepts::real_concept max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ + return max_value(); +} + +template <> +inline concepts::real_concept min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ + return min_value(); +} + +template <> +inline concepts::real_concept log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ + return log_max_value(); +} + +template <> +inline concepts::real_concept log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ + return log_min_value(); +} + +template <> +inline concepts::real_concept epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ +#ifdef __SUNPRO_CC + return std::numeric_limits::epsilon(); +#else + return tools::epsilon(); +#endif +} + +template <> +inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +{ + // Assume number of significand bits is same as long double, + // unless std::numeric_limits::is_specialized to provide digits. + return tools::digits(); + // Note that if numeric_limits real concept is NOT specialized to provide digits10 + // (or max_digits10) then the default precision of 6 decimal digits will be used + // by Boost test (giving misleading error messages like + // "difference between {9.79796} and {9.79796} exceeds 5.42101e-19%" + // and by Boost lexical cast and serialization causing loss of accuracy. +} + +} // namespace tools + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_REAL_CONCEPT_HPP + + diff --git a/include/boost/math/concepts/std_real_concept.hpp b/include/boost/math/concepts/std_real_concept.hpp new file mode 100644 index 000000000..329c35225 --- /dev/null +++ b/include/boost/math/concepts/std_real_concept.hpp @@ -0,0 +1,356 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// std_real_concept is an archetype for built-in Real types. + +// The main purpose in providing this type is to verify +// that std lib functions are found via a using declaration +// bringing those functions into the current scope, and not +// just because they happen to be in global scope. +// +// If ::pow is found rather than std::pow say, then the code +// will silently compile, but truncation of long doubles to +// double will cause a significant loss of precision. +// A template instantiated with std_real_concept will *only* +// compile if it std::whatever is in scope. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include // fmodl + +#ifndef BOOST_MATH_STD_REAL_CONCEPT_HPP +#define BOOST_MATH_STD_REAL_CONCEPT_HPP + +namespace boost{ namespace math{ + +namespace concepts +{ + +class std_real_concept +{ +public: + // Constructors: + std_real_concept() : m_value(0){} + std_real_concept(char c) : m_value(c){} +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + std_real_concept(wchar_t c) : m_value(c){} +#endif + std_real_concept(unsigned char c) : m_value(c){} + std_real_concept(signed char c) : m_value(c){} + std_real_concept(unsigned short c) : m_value(c){} + std_real_concept(short c) : m_value(c){} + std_real_concept(unsigned int c) : m_value(c){} + std_real_concept(int c) : m_value(c){} + std_real_concept(unsigned long c) : m_value(c){} + std_real_concept(long c) : m_value(c){} +#if defined(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC) + std_real_concept(unsigned long long c) : m_value(static_cast(c)){} + std_real_concept(long long c) : m_value(static_cast(c)){} +#endif + std_real_concept(float c) : m_value(c){} + std_real_concept(double c) : m_value(c){} + std_real_concept(long double c) : m_value(c){} + + // Assignment: + std_real_concept& operator=(char c) { m_value = c; return *this; } + std_real_concept& operator=(unsigned char c) { m_value = c; return *this; } + std_real_concept& operator=(signed char c) { m_value = c; return *this; } +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + std_real_concept& operator=(wchar_t c) { m_value = c; return *this; } +#endif + std_real_concept& operator=(short c) { m_value = c; return *this; } + std_real_concept& operator=(unsigned short c) { m_value = c; return *this; } + std_real_concept& operator=(int c) { m_value = c; return *this; } + std_real_concept& operator=(unsigned int c) { m_value = c; return *this; } + std_real_concept& operator=(long c) { m_value = c; return *this; } + std_real_concept& operator=(unsigned long c) { m_value = c; return *this; } +#if defined(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC) + std_real_concept& operator=(long long c) { m_value = static_cast(c); return *this; } + std_real_concept& operator=(unsigned long long c) { m_value = static_cast(c); return *this; } +#endif + std_real_concept& operator=(float c) { m_value = c; return *this; } + std_real_concept& operator=(double c) { m_value = c; return *this; } + std_real_concept& operator=(long double c) { m_value = c; return *this; } + + // Access: + long double value()const{ return m_value; } + + // Member arithmetic: + std_real_concept& operator+=(const std_real_concept& other) + { m_value += other.value(); return *this; } + std_real_concept& operator-=(const std_real_concept& other) + { m_value -= other.value(); return *this; } + std_real_concept& operator*=(const std_real_concept& other) + { m_value *= other.value(); return *this; } + std_real_concept& operator/=(const std_real_concept& other) + { m_value /= other.value(); return *this; } + std_real_concept operator-()const + { return -m_value; } + std_real_concept const& operator+()const + { return *this; } + +private: + long double m_value; +}; + +// Non-member arithmetic: +inline std_real_concept operator+(const std_real_concept& a, const std_real_concept& b) +{ + std_real_concept result(a); + result += b; + return result; +} +inline std_real_concept operator-(const std_real_concept& a, const std_real_concept& b) +{ + std_real_concept result(a); + result -= b; + return result; +} +inline std_real_concept operator*(const std_real_concept& a, const std_real_concept& b) +{ + std_real_concept result(a); + result *= b; + return result; +} +inline std_real_concept operator/(const std_real_concept& a, const std_real_concept& b) +{ + std_real_concept result(a); + result /= b; + return result; +} + +// Comparison: +inline bool operator == (const std_real_concept& a, const std_real_concept& b) +{ return a.value() == b.value(); } +inline bool operator != (const std_real_concept& a, const std_real_concept& b) +{ return a.value() != b.value();} +inline bool operator < (const std_real_concept& a, const std_real_concept& b) +{ return a.value() < b.value(); } +inline bool operator <= (const std_real_concept& a, const std_real_concept& b) +{ return a.value() <= b.value(); } +inline bool operator > (const std_real_concept& a, const std_real_concept& b) +{ return a.value() > b.value(); } +inline bool operator >= (const std_real_concept& a, const std_real_concept& b) +{ return a.value() >= b.value(); } + +#if 0 +// Non-member mixed compare: +template +inline bool operator == (const T& a, const std_real_concept& b) +{ + return a == b.value(); +} +template +inline bool operator != (const T& a, const std_real_concept& b) +{ + return a != b.value(); +} +template +inline bool operator < (const T& a, const std_real_concept& b) +{ + return a < b.value(); +} +template +inline bool operator > (const T& a, const std_real_concept& b) +{ + return a > b.value(); +} +template +inline bool operator <= (const T& a, const std_real_concept& b) +{ + return a <= b.value(); +} +template +inline bool operator >= (const T& a, const std_real_concept& b) +{ + return a >= b.value(); +} +#endif // Non-member mixed compare: + +} // namespace concepts +} // namespace math +} // namespace boost + +namespace std{ + +// Non-member functions: +inline boost::math::concepts::std_real_concept acos(boost::math::concepts::std_real_concept a) +{ return std::acos(a.value()); } +inline boost::math::concepts::std_real_concept cos(boost::math::concepts::std_real_concept a) +{ return std::cos(a.value()); } +inline boost::math::concepts::std_real_concept asin(boost::math::concepts::std_real_concept a) +{ return std::asin(a.value()); } +inline boost::math::concepts::std_real_concept atan(boost::math::concepts::std_real_concept a) +{ return std::atan(a.value()); } +inline boost::math::concepts::std_real_concept atan2(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b) +{ return std::atan2(a.value(), b.value()); } +inline boost::math::concepts::std_real_concept ceil(boost::math::concepts::std_real_concept a) +{ return std::ceil(a.value()); } +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +inline boost::math::concepts::std_real_concept fmod(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b) +{ return fmodl(a.value(), b.value()); } +#else +inline boost::math::concepts::std_real_concept fmod(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b) +{ return std::fmod(a.value(), b.value()); } +#endif +inline boost::math::concepts::std_real_concept cosh(boost::math::concepts::std_real_concept a) +{ return std::cosh(a.value()); } +inline boost::math::concepts::std_real_concept exp(boost::math::concepts::std_real_concept a) +{ return std::exp(a.value()); } +inline boost::math::concepts::std_real_concept fabs(boost::math::concepts::std_real_concept a) +{ return std::fabs(a.value()); } +inline boost::math::concepts::std_real_concept abs(boost::math::concepts::std_real_concept a) +{ return std::abs(a.value()); } +inline boost::math::concepts::std_real_concept floor(boost::math::concepts::std_real_concept a) +{ return std::floor(a.value()); } +inline boost::math::concepts::std_real_concept modf(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept* ipart) +{ + long double ip; + long double result = std::modf(a.value(), &ip); + *ipart = ip; + return result; +} +inline boost::math::concepts::std_real_concept frexp(boost::math::concepts::std_real_concept a, int* expon) +{ return std::frexp(a.value(), expon); } +inline boost::math::concepts::std_real_concept ldexp(boost::math::concepts::std_real_concept a, int expon) +{ return std::ldexp(a.value(), expon); } +inline boost::math::concepts::std_real_concept log(boost::math::concepts::std_real_concept a) +{ return std::log(a.value()); } +inline boost::math::concepts::std_real_concept log10(boost::math::concepts::std_real_concept a) +{ return std::log10(a.value()); } +inline boost::math::concepts::std_real_concept tan(boost::math::concepts::std_real_concept a) +{ return std::tan(a.value()); } +inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b) +{ return std::pow(a.value(), b.value()); } +#if !defined(__SUNPRO_CC) +inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, int b) +{ return std::pow(a.value(), b); } +#else +inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, int b) +{ return std::pow(a.value(), static_cast(b)); } +#endif +inline boost::math::concepts::std_real_concept sin(boost::math::concepts::std_real_concept a) +{ return std::sin(a.value()); } +inline boost::math::concepts::std_real_concept sinh(boost::math::concepts::std_real_concept a) +{ return std::sinh(a.value()); } +inline boost::math::concepts::std_real_concept sqrt(boost::math::concepts::std_real_concept a) +{ return std::sqrt(a.value()); } +inline boost::math::concepts::std_real_concept tanh(boost::math::concepts::std_real_concept a) +{ return std::tanh(a.value()); } + +} // namespace std + +namespace boost{ namespace math{ namespace concepts{ + +// Streaming: +template +inline std::basic_ostream& operator<<(std::basic_ostream& os, const std_real_concept& a) +{ + return os << a.value(); +} +template +inline std::basic_istream& operator>>(std::basic_istream& is, std_real_concept& a) +{ + long double v; + is >> v; + a = v; + return is; +} + +} // namespace concepts + +namespace tools +{ +// real_cast converts from T to integer and narrower floating-point types. + +// Convert from T to integer types. + +template <> +inline unsigned int real_cast(concepts::std_real_concept r) +{ + return static_cast(r.value()); +} + +template <> +inline int real_cast(concepts::std_real_concept r) +{ + return static_cast(r.value()); +} + +template <> +inline long real_cast(concepts::std_real_concept r) +{ + return static_cast(r.value()); +} + +// Converts from T to narrower floating-point types, float, double & long double. + +template <> +inline float real_cast(concepts::std_real_concept r) +{ + return static_cast(r.value()); +} +template <> +inline double real_cast(concepts::std_real_concept r) +{ + return static_cast(r.value()); +} +template <> +inline long double real_cast(concepts::std_real_concept r) +{ + return r.value(); +} + +template <> +inline concepts::std_real_concept max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ + return max_value(); +} + +template <> +inline concepts::std_real_concept min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ + return min_value(); +} + +template <> +inline concepts::std_real_concept log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ + return log_max_value(); +} + +template <> +inline concepts::std_real_concept log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ + return log_min_value(); +} + +template <> +inline concepts::std_real_concept epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ + return tools::epsilon(); +} + +template <> +inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept)) +{ // Assume number of significand bits is same as long double, + // unless std::numeric_limits::is_specialized to provide digits. + return digits(); +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_STD_REAL_CONCEPT_HPP + + diff --git a/include/boost/math/constants/constants.hpp b/include/boost/math/constants/constants.hpp new file mode 100644 index 000000000..7fb6a786d --- /dev/null +++ b/include/boost/math/constants/constants.hpp @@ -0,0 +1,75 @@ +// Copyright John Maddock 2005-2006. +// Copyright Paul A. Bristow 2006-7. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED +#define BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED + +#include +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4127 4701) +#endif +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ namespace math +{ + namespace constants + { + // To permit other calculations at about 100 decimal digits with NTL::RR type, + // it is obviously necessary to define constants to this accuracy. + + // However, some compilers do not accept decimal digits strings as long as this. + // So the constant is split into two parts, with the 1st containing at least + // long double precision, and the 2nd zero if not needed or known. + // The 3rd part permits an exponent to be provided if necessary (use zero if none) - + // the other two parameters may only contain decimal digits (and sign and decimal point), + // and may NOT include an exponent like 1.234E99. + // The second digit string is only used if T is a User-Defined Type, + // when the constant is converted to a long string literal and lexical_casted to type T. + // (This is necessary because you can't use a numeric constant + // since even a long double might not have enough digits). + + + #define BOOST_DEFINE_MATH_CONSTANT(name, x, y, exp)\ + template inline T name(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))\ + {\ + static const T result = ::boost::lexical_cast(BOOST_STRINGIZE(BOOST_JOIN(BOOST_JOIN(x, y), BOOST_JOIN(e, exp))));\ + return result;\ + }\ + template <> inline float name(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(float))\ + { return BOOST_JOIN(BOOST_JOIN(x, BOOST_JOIN(e, exp)), F); }\ + template <> inline double name(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(double))\ + { return BOOST_JOIN(x, BOOST_JOIN(e, exp)); }\ + template <> inline long double name(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))\ + { return BOOST_JOIN(BOOST_JOIN(x, BOOST_JOIN(e, exp)), L); } + + BOOST_DEFINE_MATH_CONSTANT(pi, 3.141592653589793238462643383279502884197169399375105820974944, 59230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196, 0) + BOOST_DEFINE_MATH_CONSTANT(root_pi, 1.7724538509055160272981674833411451827975, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(root_half_pi, 1.253314137315500251207882642405522626503, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(root_two_pi, 2.506628274631000502415765284811045253007, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(root_ln_four, 1.1774100225154746910115693264596996377473856893858205385225257565000, 2658854698492680841813836877081, 0) + BOOST_DEFINE_MATH_CONSTANT(e, 2.7182818284590452353602874713526624977572470936999595749669676, 27724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011, 0) + BOOST_DEFINE_MATH_CONSTANT(half, 0.5, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(euler, 0.577215664901532860606512090082402431042159335939923598805, 76723488486, 0) + BOOST_DEFINE_MATH_CONSTANT(root_two, 1.414213562373095048801688724209698078569671875376948073, 17667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206, 0) + BOOST_DEFINE_MATH_CONSTANT(ln_two, 0.693147180559945309417232121458176568075500134360255254, 120680009493393621969694715605863326996418687, 0) + BOOST_DEFINE_MATH_CONSTANT(ln_ln_two, -0.36651292058166432701243915823266946945426344783710526305367771367056, 16153193527385494558228566989083583025230453648347655663425171940646634, 0) + BOOST_DEFINE_MATH_CONSTANT(third, 0.3333333333333333333333333333333333333333333333333333333333333333333333, 3333333333333333333333333333333333333333333333333333333333333333333333333, 0) + BOOST_DEFINE_MATH_CONSTANT(twothirds, 0.66666666666666666666666666666666666666666666666666666666666666666666, 66666666666666666666666666666666666666666666666666666666666666666666667, 0) + BOOST_DEFINE_MATH_CONSTANT(pi_minus_three, 0.141592653589793238462643383279502884197169399375105820974944, 59230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196, 0) + BOOST_DEFINE_MATH_CONSTANT(four_minus_pi, 0.85840734641020676153735661672049711580283060062489417902505540769218359, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(pow23_four_minus_pi, 0.79531676737159754434839533505680658072763917332771320544530223438582161, 0, 0) + BOOST_DEFINE_MATH_CONSTANT(exp_minus_half, 0.6065306597126334236037995349911804534419181354871869556828921587350565194137, 484239986476115079894560, 0) + + + } // namespace constants +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED diff --git a/include/boost/math/distributions.hpp b/include/boost/math/distributions.hpp new file mode 100644 index 000000000..bf81c2689 --- /dev/null +++ b/include/boost/math/distributions.hpp @@ -0,0 +1,42 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This file includes *all* the distributions. +// this may be useful if many are used +// - to avoid including each distribution individually. + +#ifndef BOOST_MATH_DISTRIBUTIONS_HPP +#define BOOST_MATH_DISTRIBUTIONS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// find location and shape for appropriate distributions, +// normal, cauchy, lognormal, symmetric triangular +// Disabled for now, these are still work in progress. +//#include +//#include + +#endif // BOOST_MATH_DISTRIBUTIONS_HPP + diff --git a/include/boost/math/distributions/bernoulli.hpp b/include/boost/math/distributions/bernoulli.hpp new file mode 100644 index 000000000..aeb6c8f3a --- /dev/null +++ b/include/boost/math/distributions/bernoulli.hpp @@ -0,0 +1,325 @@ +// boost\math\distributions\bernoulli.hpp + +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// http://en.wikipedia.org/wiki/bernoulli_distribution +// http://mathworld.wolfram.com/BernoulliDistribution.html + +// bernoulli distribution is the discrete probability distribution of +// the number (k) of successes, in a single Bernoulli trials. +// It is a version of the binomial distribution when n = 1. + +// But note that the bernoulli distribution +// (like others including the poisson, binomial & negative binomial) +// is strictly defined as a discrete function: only integral values of k are envisaged. +// However because of the method of calculation using a continuous gamma function, +// it is convenient to treat it as if a continous function, +// and permit non-integral values of k. +// To enforce the strict mathematical model, users should use floor or ceil functions +// on k outside this function to ensure that k is integral. + +#ifndef BOOST_MATH_SPECIAL_BERNOULLI_HPP +#define BOOST_MATH_SPECIAL_BERNOULLI_HPP + +#include +#include +#include // complements +#include // error checks +#include // isnan. + +#include + +namespace boost +{ + namespace math + { + namespace bernoulli_detail + { + // Common error checking routines for bernoulli distribution functions: + template + inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& /* pol */) + { + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + *result = policies::raise_domain_error( + function, + "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, Policy()); + return false; + } + return true; + } + template + inline bool check_dist(const char* function, const RealType& p, RealType* result, const Policy& /* pol */) + { + return check_success_fraction(function, p, result, Policy()); + } + template + inline bool check_dist_and_k(const char* function, const RealType& p, RealType k, RealType* result, const Policy& pol) + { + if(check_dist(function, p, result, Policy()) == false) + { + return false; + } + if(!(boost::math::isfinite)(k) || !((k == 0) || (k == 1))) + { + *result = policies::raise_domain_error( + function, + "Number of successes argument is %1%, but must be 0 or 1 !", k, pol); + return false; + } + return true; + } + template + inline bool check_dist_and_prob(const char* function, RealType p, RealType prob, RealType* result, const Policy& /* pol */) + { + if(check_dist(function, p, result, Policy()) && detail::check_probability(function, prob, result, Policy()) == false) + { + return false; + } + return true; + } + } // namespace bernoulli_detail + + + template > + class bernoulli_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + bernoulli_distribution(RealType p = 0.5) : m_p(p) + { // Default probability = half suits 'fair' coin tossing + // where probability of heads == probability of tails. + RealType result; // of checks. + bernoulli_detail::check_dist( + "boost::math::bernoulli_distribution<%1%>::bernoulli_distribution", + m_p, + &result, Policy()); + } // bernoulli_distribution constructor. + + RealType success_fraction() const + { // Probability. + return m_p; + } + + private: + RealType m_p; // success_fraction + }; // template class bernoulli_distribution + + typedef bernoulli_distribution bernoulli; + + template + inline const std::pair range(const bernoulli_distribution& /* dist */) + { // Range of permissible values for random variable k = {0, 1}. + using boost::math::tools::max_value; + return std::pair(0, 1); + } + + template + inline const std::pair support(const bernoulli_distribution& /* dist */) + { // Range of supported values for random variable k = {0, 1}. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(0, 1); + } + + template + inline RealType mean(const bernoulli_distribution& dist) + { // Mean of bernoulli distribution = p (n = 1). + return dist.success_fraction(); + } // mean + + // Rely on dereived_accessors quantile(half) + //template + //inline RealType median(const bernoulli_distribution& dist) + //{ // Median of bernoulli distribution is not defined. + // return tools::domain_error(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits::quiet_NaN()); + //} // median + + template + inline RealType variance(const bernoulli_distribution& dist) + { // Variance of bernoulli distribution =p * q. + return dist.success_fraction() * (1 - dist.success_fraction()); + } // variance + + template + RealType pdf(const bernoulli_distribution& dist, const RealType& k) + { // Probability Density/Mass Function. + BOOST_FPU_EXCEPTION_GUARD + // Error check: + RealType result; // of checks. + if(false == bernoulli_detail::check_dist_and_k( + "boost::math::pdf(bernoulli_distribution<%1%>, %1%)", + dist.success_fraction(), // 0 to 1 + k, // 0 or 1 + &result, Policy())) + { + return result; + } + // Assume k is integral. + if (k == 0) + { + return 1 - dist.success_fraction(); // 1 - p + } + else // k == 1 + { + return dist.success_fraction(); // p + } + } // pdf + + template + inline RealType cdf(const bernoulli_distribution& dist, const RealType& k) + { // Cumulative Distribution Function Bernoulli. + RealType p = dist.success_fraction(); + // Error check: + RealType result; + if(false == bernoulli_detail::check_dist_and_k( + "boost::math::cdf(bernoulli_distribution<%1%>, %1%)", + p, + k, + &result, Policy())) + { + return result; + } + if (k == 0) + { + return 1 - p; + } + else + { // k == 1 + return 1; + } + } // bernoulli cdf + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function bernoulli. + RealType const& k = c.param; + bernoulli_distribution const& dist = c.dist; + RealType p = dist.success_fraction(); + // Error checks: + RealType result; + if(false == bernoulli_detail::check_dist_and_k( + "boost::math::cdf(bernoulli_distribution<%1%>, %1%)", + p, + k, + &result, Policy())) + { + return result; + } + if (k == 0) + { + return p; + } + else + { // k == 1 + return 0; + } + } // bernoulli cdf complement + + template + inline RealType quantile(const bernoulli_distribution& dist, const RealType& p) + { // Quantile or Percent Point Bernoulli function. + // Return the number of expected successes k either 0 or 1. + // for a given probability p. + + RealType result; // of error checks: + if(false == bernoulli_detail::check_dist_and_prob( + "boost::math::quantile(bernoulli_distribution<%1%>, %1%)", + dist.success_fraction(), + p, + &result, Policy())) + { + return result; + } + if (p <= (1 - dist.success_fraction())) + { // p <= pdf(dist, 0) == cdf(dist, 0) + return 0; + } + else + { + return 1; + } + } // quantile + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { // Quantile or Percent Point bernoulli function. + // Return the number of expected successes k for a given + // complement of the probability q. + // + // Error checks: + RealType q = c.param; + const bernoulli_distribution& dist = c.dist; + RealType result; + if(false == bernoulli_detail::check_dist_and_prob( + "boost::math::quantile(bernoulli_distribution<%1%>, %1%)", + dist.success_fraction(), + q, + &result, Policy())) + { + return result; + } + + if (q <= 1 - dist.success_fraction()) + { // // q <= cdf(complement(dist, 0)) == pdf(dist, 0) + return 1; + } + else + { + return 0; + } + } // quantile complemented. + + template + inline RealType mode(const bernoulli_distribution& dist) + { + return static_cast((dist.success_fraction() <= 0.5) ? 0 : 1); // p = 0.5 can be 0 or 1 + } + + template + inline RealType skewness(const bernoulli_distribution& dist) + { + BOOST_MATH_STD_USING; // Aid ADL for sqrt. + RealType p = dist.success_fraction(); + return (1 - 2 * p) / sqrt(p * (1 - p)); + } + + template + inline RealType kurtosis_excess(const bernoulli_distribution& dist) + { + RealType p = dist.success_fraction(); + // Note Wolfram says this is kurtosis in text, but gamma2 is the kurtosis excess, + // and Wikipedia also says this is the kurtosis excess formula. + // return (6 * p * p - 6 * p + 1) / (p * (1 - p)); + // But Wolfram kurtosis article gives this simpler formula for kurtosis excess: + return 1 / (1 - p) + 1/p -6; + } + + template + inline RealType kurtosis(const bernoulli_distribution& dist) + { + RealType p = dist.success_fraction(); + return 1 / (1 - p) + 1/p -6 + 3; + // Simpler than: + // return (6 * p * p - 6 * p + 1) / (p * (1 - p)) + 3; + } + + } // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_MATH_SPECIAL_BERNOULLI_HPP + + + diff --git a/include/boost/math/distributions/beta.hpp b/include/boost/math/distributions/beta.hpp new file mode 100644 index 000000000..d1b753c3a --- /dev/null +++ b/include/boost/math/distributions/beta.hpp @@ -0,0 +1,544 @@ +// boost\math\distributions\beta.hpp + +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2006. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// http://en.wikipedia.org/wiki/Beta_distribution +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm +// http://mathworld.wolfram.com/BetaDistribution.html + +// The Beta Distribution is a continuous probability distribution. +// The beta distribution is used to model events which are constrained to take place +// within an interval defined by maxima and minima, +// so is used extensively in PERT and other project management systems +// to describe the time to completion. +// The cdf of the beta distribution is used as a convenient way +// of obtaining the sum over a set of binomial outcomes. +// The beta distribution is also used in Bayesian statistics. + +#ifndef BOOST_MATH_DIST_BETA_HPP +#define BOOST_MATH_DIST_BETA_HPP + +#include +#include // for beta. +#include // complements. +#include // error checks +#include // isnan. +#include // for root finding. + +#if defined (BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code +// in domain_error_imp in error_handling +#endif + +#include + +namespace boost +{ + namespace math + { + namespace beta_detail + { + // Common error checking routines for beta distribution functions: + template + inline bool check_alpha(const char* function, const RealType& alpha, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(alpha) || (alpha <= 0)) + { + *result = policies::raise_domain_error( + function, + "Alpha argument is %1%, but must be > 0 !", alpha, pol); + return false; + } + return true; + } // bool check_alpha + + template + inline bool check_beta(const char* function, const RealType& beta, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(beta) || (beta <= 0)) + { + *result = policies::raise_domain_error( + function, + "Beta argument is %1%, but must be > 0 !", beta, pol); + return false; + } + return true; + } // bool check_beta + + template + inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol) + { + if((p < 0) || (p > 1) || !(boost::math::isfinite)(p)) + { + *result = policies::raise_domain_error( + function, + "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol); + return false; + } + return true; + } // bool check_prob + + template + inline bool check_x(const char* function, const RealType& x, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(x) || (x < 0) || (x > 1)) + { + *result = policies::raise_domain_error( + function, + "x argument is %1%, but must be >= 0 and <= 1 !", x, pol); + return false; + } + return true; + } // bool check_x + + template + inline bool check_dist(const char* function, const RealType& alpha, const RealType& beta, RealType* result, const Policy& pol) + { // Check both alpha and beta. + return check_alpha(function, alpha, result, pol) + && check_beta(function, beta, result, pol); + } // bool check_dist + + template + inline bool check_dist_and_x(const char* function, const RealType& alpha, const RealType& beta, RealType x, RealType* result, const Policy& pol) + { + return check_dist(function, alpha, beta, result, pol) + && check_x(function, x, result, pol); + } // bool check_dist_and_x + + template + inline bool check_dist_and_prob(const char* function, const RealType& alpha, const RealType& beta, RealType p, RealType* result, const Policy& pol) + { + return check_dist(function, alpha, beta, result, pol) + && check_prob(function, p, result, pol); + } // bool check_dist_and_prob + + template + inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(mean) || (mean <= 0)) + { + *result = policies::raise_domain_error( + function, + "mean argument is %1%, but must be > 0 !", mean, pol); + return false; + } + return true; + } // bool check_mean + template + inline bool check_variance(const char* function, const RealType& variance, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(variance) || (variance <= 0)) + { + *result = policies::raise_domain_error( + function, + "variance argument is %1%, but must be > 0 !", variance, pol); + return false; + } + return true; + } // bool check_variance + } // namespace beta_detail + + // typedef beta_distribution beta; + // is deliberately NOT included to avoid a name clash with the beta function. + // Use beta_distribution<> mybeta(...) to construct type double. + + template > + class beta_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + beta_distribution(RealType alpha = 1, RealType beta = 1) : m_alpha(alpha), m_beta(beta) + { + RealType result; + beta_detail::check_dist( + "boost::math::beta_distribution<%1%>::beta_distribution", + m_alpha, + m_beta, + &result, Policy()); + } // beta_distribution constructor. + // Accessor functions: + RealType alpha() const + { + return m_alpha; + } + RealType beta() const + { // . + return m_beta; + } + + // Estimation of the alpha & beta parameters. + // http://en.wikipedia.org/wiki/Beta_distribution + // gives formulae in section on parameter estimation. + // Also NIST EDA page 3 & 4 give the same. + // http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm + // http://www.epi.ucdavis.edu/diagnostictests/betabuster.html + + static RealType find_alpha( + RealType mean, // Expected value of mean. + RealType variance) // Expected value of variance. + { + static const char* function = "boost::math::beta_distribution<%1%>::find_alpha"; + RealType result; // of error checks. + if(false == + beta_detail::check_mean( + function, mean, &result, Policy()) + && + beta_detail::check_variance( + function, variance, &result, Policy()) + ) + { + return result; + } + return mean * (( (mean * (1 - mean)) / variance)- 1); + } // RealType find_alpha + + static RealType find_beta( + RealType mean, // Expected value of mean. + RealType variance) // Expected value of variance. + { + static const char* function = "boost::math::beta_distribution<%1%>::find_beta"; + RealType result; // of error checks. + if(false == + beta_detail::check_mean( + function, mean, &result, Policy()) + && + beta_detail::check_variance( + function, variance, &result, Policy()) + ) + { + return result; + } + return (1 - mean) * (((mean * (1 - mean)) /variance)-1); + } // RealType find_beta + + // Estimate alpha & beta from either alpha or beta, and x and probability. + // Uses for these parameter estimators are unclear. + + static RealType find_alpha( + RealType beta, // from beta. + RealType x, // x. + RealType probability) // cdf + { + static const char* function = "boost::math::beta_distribution<%1%>::find_alpha"; + RealType result; // of error checks. + if(false == + beta_detail::check_prob( + function, probability, &result, Policy()) + && + beta_detail::check_beta( + function, beta, &result, Policy()) + && + beta_detail::check_x( + function, x, &result, Policy()) + ) + { + return result; + } + return ibeta_inva(beta, x, probability, Policy()); + } // RealType find_alpha(beta, a, probability) + + static RealType find_beta( + // ibeta_invb(T b, T x, T p); (alpha, x, cdf,) + RealType alpha, // alpha. + RealType x, // probability x. + RealType probability) // probability cdf. + { + static const char* function = "boost::math::beta_distribution<%1%>::find_beta"; + RealType result; // of error checks. + if(false == + beta_detail::check_prob( + function, probability, &result, Policy()) + && + beta_detail::check_alpha( + function, alpha, &result, Policy()) + && + beta_detail::check_x( + function, x, &result, Policy()) + ) + { + return result; + } + return ibeta_invb(alpha, x, probability, Policy()); + } // RealType find_beta(alpha, x, probability) + + private: + RealType m_alpha; // Two parameters of the beta distribution. + RealType m_beta; + }; // template class beta_distribution + + template + inline const std::pair range(const beta_distribution& /* dist */) + { // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, 1); + } + + template + inline const std::pair support(const beta_distribution& /* dist */) + { // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(0, 1); + } + + template + inline RealType mean(const beta_distribution& dist) + { // Mean of beta distribution = np. + return dist.alpha() / (dist.alpha() + dist.beta()); + } // mean + + template + inline RealType variance(const beta_distribution& dist) + { // Variance of beta distribution = np(1-p). + RealType a = dist.alpha(); + RealType b = dist.beta(); + return (a * b) / ((a + b ) * (a + b) * (a + b + 1)); + } // variance + + template + inline RealType mode(const beta_distribution& dist) + { + static const char* function = "boost::math::mode(beta_distribution<%1%> const&)"; + + RealType result; + if ((dist.alpha() <= 1)) + { + result = policies::raise_domain_error( + function, + "mode undefined for alpha = %1%, must be > 1!", dist.alpha(), Policy()); + return result; + } + + if ((dist.beta() <= 1)) + { + result = policies::raise_domain_error( + function, + "mode undefined for beta = %1%, must be > 1!", dist.beta(), Policy()); + return result; + } + RealType a = dist.alpha(); + RealType b = dist.beta(); + return (a-1) / (a + b - 2); + } // mode + + //template + //inline RealType median(const beta_distribution& dist) + //{ // Median of beta distribution is not defined. + // return tools::domain_error(function, "Median is not implemented, result is %1%!", std::numeric_limits::quiet_NaN()); + //} // median + + //But WILL be provided by the derived accessor as quantile(0.5). + + template + inline RealType skewness(const beta_distribution& dist) + { + BOOST_MATH_STD_USING // ADL of std functions. + RealType a = dist.alpha(); + RealType b = dist.beta(); + return (2 * (b-a) * sqrt(a + b + 1)) / ((a + b + 2) * sqrt(a * b)); + } // skewness + + template + inline RealType kurtosis_excess(const beta_distribution& dist) + { + RealType a = dist.alpha(); + RealType b = dist.beta(); + RealType a_2 = a * a; + RealType n = 6 * (a_2 * a - a_2 * (2 * b - 1) + b * b * (b + 1) - 2 * a * b * (b + 2)); + RealType d = a * b * (a + b + 2) * (a + b + 3); + return n / d; + } // kurtosis_excess + + template + inline RealType kurtosis(const beta_distribution& dist) + { + return 3 + kurtosis_excess(dist); + } // kurtosis + + template + inline RealType pdf(const beta_distribution& dist, const RealType& x) + { // Probability Density/Mass Function. + BOOST_FPU_EXCEPTION_GUARD + + static const char* function = "boost::math::pdf(beta_distribution<%1%> const&, %1%)"; + + BOOST_MATH_STD_USING // for ADL of std functions + + RealType a = dist.alpha(); + RealType b = dist.beta(); + + // Argument checks: + RealType result; + if(false == beta_detail::check_dist_and_x( + function, + a, b, x, + &result, Policy())) + { + return result; + } + using boost::math::beta; + return ibeta_derivative(a, b, x, Policy()); + } // pdf + + template + inline RealType cdf(const beta_distribution& dist, const RealType& x) + { // Cumulative Distribution Function beta. + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)"; + + RealType a = dist.alpha(); + RealType b = dist.beta(); + + // Argument checks: + RealType result; + if(false == beta_detail::check_dist_and_x( + function, + a, b, x, + &result, Policy())) + { + return result; + } + // Special cases: + if (x == 0) + { + return 0; + } + else if (x == 1) + { + return 1; + } + return ibeta(a, b, x, Policy()); + } // beta cdf + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function beta. + + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)"; + + RealType const& x = c.param; + beta_distribution const& dist = c.dist; + RealType a = dist.alpha(); + RealType b = dist.beta(); + + // Argument checks: + RealType result; + if(false == beta_detail::check_dist_and_x( + function, + a, b, x, + &result, Policy())) + { + return result; + } + if (x == 0) + { + return 1; + } + else if (x == 1) + { + return 0; + } + // Calculate cdf beta using the incomplete beta function. + // Use of ibeta here prevents cancellation errors in calculating + // 1 - x if x is very small, perhaps smaller than machine epsilon. + return ibetac(a, b, x, Policy()); + } // beta cdf + + template + inline RealType quantile(const beta_distribution& dist, const RealType& p) + { // Quantile or Percent Point beta function or + // Inverse Cumulative probability distribution function CDF. + // Return x (0 <= x <= 1), + // for a given probability p (0 <= p <= 1). + // These functions take a probability as an argument + // and return a value such that the probability that a random variable x + // will be less than or equal to that value + // is whatever probability you supplied as an argument. + + static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)"; + + RealType result; // of argument checks: + RealType a = dist.alpha(); + RealType b = dist.beta(); + if(false == beta_detail::check_dist_and_prob( + function, + a, b, p, + &result, Policy())) + { + return result; + } + // Special cases: + if (p == 0) + { + return 0; + } + if (p == 1) + { + return 1; + } + return ibeta_inv(a, b, p, static_cast(0), Policy()); + } // quantile + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { // Complement Quantile or Percent Point beta function . + // Return the number of expected x for a given + // complement of the probability q. + + static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)"; + + // + // Error checks: + RealType q = c.param; + const beta_distribution& dist = c.dist; + RealType result; + RealType a = dist.alpha(); + RealType b = dist.beta(); + if(false == beta_detail::check_dist_and_prob( + function, + a, + b, + q, + &result, Policy())) + { + return result; + } + // Special cases: + if(q == 1) + { + return 0; + } + if(q == 0) + { + return 1; + } + + return ibetac_inv(a, b, q, static_cast(0), Policy()); + } // Quantile Complement + + } // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#if defined (BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif // BOOST_MATH_DIST_BETA_HPP + + diff --git a/include/boost/math/distributions/binomial.hpp b/include/boost/math/distributions/binomial.hpp new file mode 100644 index 000000000..36000adb2 --- /dev/null +++ b/include/boost/math/distributions/binomial.hpp @@ -0,0 +1,724 @@ +// boost\math\distributions\binomial.hpp + +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// http://en.wikipedia.org/wiki/binomial_distribution + +// Binomial distribution is the discrete probability distribution of +// the number (k) of successes, in a sequence of +// n independent (yes or no, success or failure) Bernoulli trials. + +// It expresses the probability of a number of events occurring in a fixed time +// if these events occur with a known average rate (probability of success), +// and are independent of the time since the last event. + +// The number of cars that pass through a certain point on a road during a given period of time. +// The number of spelling mistakes a secretary makes while typing a single page. +// The number of phone calls at a call center per minute. +// The number of times a web server is accessed per minute. +// The number of light bulbs that burn out in a certain amount of time. +// The number of roadkill found per unit length of road + +// http:/en.wikipedia.org/wiki/binomial_distribution + +// Given a sample of N measured values k[i], +// we wish to estimate the value of the parameter x (mean) +// of the binomial population from which the sample was drawn. +// To calculate the maximum likelihood value = 1/N sum i = 1 to N of k[i] + +// Also may want a function for EXACTLY k. + +// And probability that there are EXACTLY k occurrences is +// exp(-x) * pow(x, k) / factorial(k) +// where x is expected occurrences (mean) during the given interval. +// For example, if events occur, on average, every 4 min, +// and we are interested in number of events occurring in 10 min, +// then x = 10/4 = 2.5 + +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366i.htm + +// The binomial distribution is used when there are +// exactly two mutually exclusive outcomes of a trial. +// These outcomes are appropriately labeled "success" and "failure". +// The binomial distribution is used to obtain +// the probability of observing x successes in N trials, +// with the probability of success on a single trial denoted by p. +// The binomial distribution assumes that p is fixed for all trials. + +// P(x, p, n) = n!/(x! * (n-x)!) * p^x * (1-p)^(n-x) + +// http://mathworld.wolfram.com/BinomialCoefficient.html + +// The binomial coefficient (n; k) is the number of ways of picking +// k unordered outcomes from n possibilities, +// also known as a combination or combinatorial number. +// The symbols _nC_k and (n; k) are used to denote a binomial coefficient, +// and are sometimes read as "n choose k." +// (n; k) therefore gives the number of k-subsets possible out of a set of n distinct items. + +// For example: +// The 2-subsets of {1,2,3,4} are the six pairs {1,2}, {1,3}, {1,4}, {2,3}, {2,4}, and {3,4}, so (4; 2)==6. + +// http://functions.wolfram.com/GammaBetaErf/Binomial/ for evaluation. + +// But note that the binomial distribution +// (like others including the poisson, negative binomial & Bernoulli) +// is strictly defined as a discrete function: only integral values of k are envisaged. +// However because of the method of calculation using a continuous gamma function, +// it is convenient to treat it as if a continous function, +// and permit non-integral values of k. +// To enforce the strict mathematical model, users should use floor or ceil functions +// on k outside this function to ensure that k is integral. + +#ifndef BOOST_MATH_SPECIAL_BINOMIAL_HPP +#define BOOST_MATH_SPECIAL_BINOMIAL_HPP + +#include +#include // for incomplete beta. +#include // complements +#include // error checks +#include // error checks +#include // isnan. +#include // for root finding. + +#include + +namespace boost +{ + namespace math + { + + template + class binomial_distribution; + + namespace binomial_detail{ + // common error checking routines for binomial distribution functions: + template + inline bool check_N(const char* function, const RealType& N, RealType* result, const Policy& pol) + { + if((N < 0) || !(boost::math::isfinite)(N)) + { + *result = policies::raise_domain_error( + function, + "Number of Trials argument is %1%, but must be >= 0 !", N, pol); + return false; + } + return true; + } + template + inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol) + { + if((p < 0) || (p > 1) || !(boost::math::isfinite)(p)) + { + *result = policies::raise_domain_error( + function, + "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol); + return false; + } + return true; + } + template + inline bool check_dist(const char* function, const RealType& N, const RealType& p, RealType* result, const Policy& pol) + { + return check_success_fraction( + function, p, result, pol) + && check_N( + function, N, result, pol); + } + template + inline bool check_dist_and_k(const char* function, const RealType& N, const RealType& p, RealType k, RealType* result, const Policy& pol) + { + if(check_dist(function, N, p, result, pol) == false) + return false; + if((k < 0) || !(boost::math::isfinite)(k)) + { + *result = policies::raise_domain_error( + function, + "Number of Successes argument is %1%, but must be >= 0 !", k, pol); + return false; + } + if(k > N) + { + *result = policies::raise_domain_error( + function, + "Number of Successes argument is %1%, but must be <= Number of Trials !", k, pol); + return false; + } + return true; + } + template + inline bool check_dist_and_prob(const char* function, const RealType& N, RealType p, RealType prob, RealType* result, const Policy& pol) + { + if(check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol) == false) + return false; + return true; + } + + template + T inverse_binomial_cornish_fisher(T n, T sf, T p, T q, const Policy& pol) + { + BOOST_MATH_STD_USING + // mean: + T m = n * sf; + // standard deviation: + T sigma = sqrt(n * sf * (1 - sf)); + // skewness + T sk = (1 - 2 * sf) / sigma; + // kurtosis: + // T k = (1 - 6 * sf * (1 - sf) ) / (n * sf * (1 - sf)); + // Get the inverse of a std normal distribution: + T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two(); + // Set the sign: + if(p < 0.5) + x = -x; + T x2 = x * x; + // w is correction term due to skewness + T w = x + sk * (x2 - 1) / 6; + /* + // Add on correction due to kurtosis. + // Disabled for now, seems to make things worse? + // + if(n >= 10) + w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36; + */ + w = m + sigma * w; + if(w < tools::min_value()) + return sqrt(tools::min_value()); + if(w > n) + return n; + return w; + } + + template + RealType quantile_imp(const binomial_distribution& dist, const RealType& p, const RealType& q) + { // Quantile or Percent Point Binomial function. + // Return the number of expected successes k, + // for a given probability p. + // + // Error checks: + BOOST_MATH_STD_USING // ADL of std names + RealType result; + RealType trials = dist.trials(); + RealType success_fraction = dist.success_fraction(); + if(false == binomial_detail::check_dist_and_prob( + "boost::math::quantile(binomial_distribution<%1%> const&, %1%)", + trials, + success_fraction, + p, + &result, Policy())) + { + return result; + } + + // Special cases: + // + if(p == 0) + { // There may actually be no answer to this question, + // since the probability of zero successes may be non-zero, + // but zero is the best we can do: + return 0; + } + if(p == 1) + { // Probability of n or fewer successes is always one, + // so n is the most sensible answer here: + return trials; + } + if (p <= pow(1 - success_fraction, trials)) + { // p <= pdf(dist, 0) == cdf(dist, 0) + return 0; // So the only reasonable result is zero. + } // And root finder would fail otherwise. + + // Solve for quantile numerically: + // + RealType guess = binomial_detail::inverse_binomial_cornish_fisher(trials, success_fraction, p, q, Policy()); + RealType factor = 8; + if(trials > 100) + factor = 1.01f; // guess is pretty accurate + else if((trials > 10) && (trials - 1 > guess) && (guess > 3)) + factor = 1.15f; // less accurate but OK. + else if(trials < 10) + { + // pretty inaccurate guess in this area: + if(guess > trials / 64) + { + guess = trials / 4; + factor = 2; + } + else + guess = trials / 1024; + } + else + factor = 2; // trials largish, but in far tails. + + typedef typename Policy::discrete_quantile_type discrete_quantile_type; + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + return detail::inverse_discrete_quantile( + dist, + p, + q, + guess, + factor, + RealType(1), + discrete_quantile_type(), + max_iter); + } // quantile + + } + + template > + class binomial_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + binomial_distribution(RealType n = 1, RealType p = 0.5) : m_n(n), m_p(p) + { // Default n = 1 is the Bernoulli distribution + // with equal probability of 'heads' or 'tails. + RealType r; + binomial_detail::check_dist( + "boost::math::binomial_distribution<%1%>::binomial_distribution", + m_n, + m_p, + &r, Policy()); + } // binomial_distribution constructor. + + RealType success_fraction() const + { // Probability. + return m_p; + } + RealType trials() const + { // Total number of trials. + return m_n; + } + + enum interval_type{ + clopper_pearson_exact_interval, + jeffreys_prior_interval + }; + + // + // Estimation of the success fraction parameter. + // The best estimate is actually simply successes/trials, + // these functions are used + // to obtain confidence intervals for the success fraction. + // + static RealType find_lower_bound_on_p( + RealType trials, + RealType successes, + RealType probability, + interval_type t = clopper_pearson_exact_interval) + { + static const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p"; + // Error checks: + RealType result; + if(false == binomial_detail::check_dist_and_k( + function, trials, RealType(0), successes, &result, Policy()) + && + binomial_detail::check_dist_and_prob( + function, trials, RealType(0), probability, &result, Policy())) + { return result; } + + if(successes == 0) + return 0; + + // NOTE!!! The Clopper Pearson formula uses "successes" not + // "successes+1" as usual to get the lower bound, + // see http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm + return (t == clopper_pearson_exact_interval) ? ibeta_inv(successes, trials - successes + 1, probability, static_cast(0), Policy()) + : ibeta_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast(0), Policy()); + } + static RealType find_upper_bound_on_p( + RealType trials, + RealType successes, + RealType probability, + interval_type t = clopper_pearson_exact_interval) + { + static const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p"; + // Error checks: + RealType result; + if(false == binomial_detail::check_dist_and_k( + function, trials, RealType(0), successes, &result, Policy()) + && + binomial_detail::check_dist_and_prob( + function, trials, RealType(0), probability, &result, Policy())) + { return result; } + + if(trials == successes) + return 1; + + return (t == clopper_pearson_exact_interval) ? ibetac_inv(successes + 1, trials - successes, probability, static_cast(0), Policy()) + : ibetac_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast(0), Policy()); + } + // Estimate number of trials parameter: + // + // "How many trials do I need to be P% sure of seeing k events?" + // or + // "How many trials can I have to be P% sure of seeing fewer than k events?" + // + static RealType find_minimum_number_of_trials( + RealType k, // number of events + RealType p, // success fraction + RealType alpha) // risk level + { + static const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials"; + // Error checks: + RealType result; + if(false == binomial_detail::check_dist_and_k( + function, k, p, k, &result, Policy()) + && + binomial_detail::check_dist_and_prob( + function, k, p, alpha, &result, Policy())) + { return result; } + + result = ibetac_invb(k + 1, p, alpha, Policy()); // returns n - k + return result + k; + } + + static RealType find_maximum_number_of_trials( + RealType k, // number of events + RealType p, // success fraction + RealType alpha) // risk level + { + static const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials"; + // Error checks: + RealType result; + if(false == binomial_detail::check_dist_and_k( + function, k, p, k, &result, Policy()) + && + binomial_detail::check_dist_and_prob( + function, k, p, alpha, &result, Policy())) + { return result; } + + result = ibeta_invb(k + 1, p, alpha, Policy()); // returns n - k + return result + k; + } + + private: + RealType m_n; // Not sure if this shouldn't be an int? + RealType m_p; // success_fraction + }; // template class binomial_distribution + + typedef binomial_distribution<> binomial; + // typedef binomial_distribution binomial; + // IS now included since no longer a name clash with function binomial. + //typedef binomial_distribution binomial; // Reserved name of type double. + + template + const std::pair range(const binomial_distribution& dist) + { // Range of permissible values for random variable k. + using boost::math::tools::max_value; + return std::pair(static_cast(0), dist.trials()); + } + + template + const std::pair support(const binomial_distribution& dist) + { // Range of supported values for random variable k. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(0, dist.trials()); + } + + template + inline RealType mean(const binomial_distribution& dist) + { // Mean of Binomial distribution = np. + return dist.trials() * dist.success_fraction(); + } // mean + + template + inline RealType variance(const binomial_distribution& dist) + { // Variance of Binomial distribution = np(1-p). + return dist.trials() * dist.success_fraction() * (1 - dist.success_fraction()); + } // variance + + template + RealType pdf(const binomial_distribution& dist, const RealType& k) + { // Probability Density/Mass Function. + BOOST_FPU_EXCEPTION_GUARD + + BOOST_MATH_STD_USING // for ADL of std functions + + RealType n = dist.trials(); + + // Error check: + RealType result; + if(false == binomial_detail::check_dist_and_k( + "boost::math::pdf(binomial_distribution<%1%> const&, %1%)", + n, + dist.success_fraction(), + k, + &result, Policy())) + { + return result; + } + + // Special cases of success_fraction, regardless of k successes and regardless of n trials. + if (dist.success_fraction() == 0) + { // probability of zero successes is 1: + return static_cast(k == 0 ? 1 : 0); + } + if (dist.success_fraction() == 1) + { // probability of n successes is 1: + return static_cast(k == n ? 1 : 0); + } + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + if (n == 0) + { + return 1; // Probability = 1 = certainty. + } + if (k == 0) + { // binomial coeffic (n 0) = 1, + // n ^ 0 = 1 + return pow(1 - dist.success_fraction(), n); + } + if (k == n) + { // binomial coeffic (n n) = 1, + // n ^ 0 = 1 + return pow(dist.success_fraction(), k); // * pow((1 - dist.success_fraction()), (n - k)) = 1 + } + + // Probability of getting exactly k successes + // if C(n, k) is the binomial coefficient then: + // + // f(k; n,p) = C(n, k) * p^k * (1-p)^(n-k) + // = (n!/(k!(n-k)!)) * p^k * (1-p)^(n-k) + // = (tgamma(n+1) / (tgamma(k+1)*tgamma(n-k+1))) * p^k * (1-p)^(n-k) + // = p^k (1-p)^(n-k) / (beta(k+1, n-k+1) * (n+1)) + // = ibeta_derivative(k+1, n-k+1, p) / (n+1) + // + using boost::math::ibeta_derivative; // a, b, x + return ibeta_derivative(k+1, n-k+1, dist.success_fraction(), Policy()) / (n+1); + + } // pdf + + template + inline RealType cdf(const binomial_distribution& dist, const RealType& k) + { // Cumulative Distribution Function Binomial. + // The random variate k is the number of successes in n trials. + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + + // Returns the sum of the terms 0 through k of the Binomial Probability Density/Mass: + // + // i=k + // -- ( n ) i n-i + // > | | p (1-p) + // -- ( i ) + // i=0 + + // The terms are not summed directly instead + // the incomplete beta integral is employed, + // according to the formula: + // P = I[1-p]( n-k, k+1). + // = 1 - I[p](k + 1, n - k) + + BOOST_MATH_STD_USING // for ADL of std functions + + RealType n = dist.trials(); + RealType p = dist.success_fraction(); + + // Error check: + RealType result; + if(false == binomial_detail::check_dist_and_k( + "boost::math::cdf(binomial_distribution<%1%> const&, %1%)", + n, + p, + k, + &result, Policy())) + { + return result; + } + if (k == n) + { + return 1; + } + + // Special cases, regardless of k. + if (p == 0) + { // This need explanation: + // the pdf is zero for all cases except when k == 0. + // For zero p the probability of zero successes is one. + // Therefore the cdf is always 1: + // the probability of k or *fewer* successes is always 1 + // if there are never any successes! + return 1; + } + if (p == 1) + { // This is correct but needs explanation: + // when k = 1 + // all the cdf and pdf values are zero *except* when k == n, + // and that case has been handled above already. + return 0; + } + // + // P = I[1-p](n - k, k + 1) + // = 1 - I[p](k + 1, n - k) + // Use of ibetac here prevents cancellation errors in calculating + // 1-p if p is very small, perhaps smaller than machine epsilon. + // + // Note that we do not use a finite sum here, since the incomplete + // beta uses a finite sum internally for integer arguments, so + // we'll just let it take care of the necessary logic. + // + return ibetac(k + 1, n - k, p, Policy()); + } // binomial cdf + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function Binomial. + // The random variate k is the number of successes in n trials. + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + + // Returns the sum of the terms k+1 through n of the Binomial Probability Density/Mass: + // + // i=n + // -- ( n ) i n-i + // > | | p (1-p) + // -- ( i ) + // i=k+1 + + // The terms are not summed directly instead + // the incomplete beta integral is employed, + // according to the formula: + // Q = 1 -I[1-p]( n-k, k+1). + // = I[p](k + 1, n - k) + + BOOST_MATH_STD_USING // for ADL of std functions + + RealType const& k = c.param; + binomial_distribution const& dist = c.dist; + RealType n = dist.trials(); + RealType p = dist.success_fraction(); + + // Error checks: + RealType result; + if(false == binomial_detail::check_dist_and_k( + "boost::math::cdf(binomial_distribution<%1%> const&, %1%)", + n, + p, + k, + &result, Policy())) + { + return result; + } + + if (k == n) + { // Probability of greater than n successes is necessarily zero: + return 0; + } + + // Special cases, regardless of k. + if (p == 0) + { + // This need explanation: the pdf is zero for all + // cases except when k == 0. For zero p the probability + // of zero successes is one. Therefore the cdf is always + // 1: the probability of *more than* k successes is always 0 + // if there are never any successes! + return 0; + } + if (p == 1) + { + // This needs explanation, when p = 1 + // we always have n successes, so the probability + // of more than k successes is 1 as long as k < n. + // The k == n case has already been handled above. + return 1; + } + // + // Calculate cdf binomial using the incomplete beta function. + // Q = 1 -I[1-p](n - k, k + 1) + // = I[p](k + 1, n - k) + // Use of ibeta here prevents cancellation errors in calculating + // 1-p if p is very small, perhaps smaller than machine epsilon. + // + // Note that we do not use a finite sum here, since the incomplete + // beta uses a finite sum internally for integer arguments, so + // we'll just let it take care of the necessary logic. + // + return ibeta(k + 1, n - k, p, Policy()); + } // binomial cdf + + template + inline RealType quantile(const binomial_distribution& dist, const RealType& p) + { + return binomial_detail::quantile_imp(dist, p, 1-p); + } // quantile + + template + RealType quantile(const complemented2_type, RealType>& c) + { + return binomial_detail::quantile_imp(c.dist, 1-c.param, c.param); + } // quantile + + template + inline RealType mode(const binomial_distribution& dist) + { + BOOST_MATH_STD_USING // ADL of std functions. + RealType p = dist.success_fraction(); + RealType n = dist.trials(); + return floor(p * (n + 1)); + } + + template + inline RealType median(const binomial_distribution& dist) + { // Bounds for the median of the negative binomial distribution + // VAN DE VEN R. ; WEBER N. C. ; + // Univ. Sydney, school mathematics statistics, Sydney N.S.W. 2006, AUSTRALIE + // Metrika (Metrika) ISSN 0026-1335 CODEN MTRKA8 + // 1993, vol. 40, no3-4, pp. 185-189 (4 ref.) + + // Bounds for median and 50 percetage point of binomial and negative binomial distribution + // Metrika, ISSN 0026-1335 (Print) 1435-926X (Online) + // Volume 41, Number 1 / December, 1994, DOI 10.1007/BF01895303 + BOOST_MATH_STD_USING // ADL of std functions. + RealType p = dist.success_fraction(); + RealType n = dist.trials(); + // Wikipedia says one of floor(np) -1, floor (np), floor(np) +1 + return floor(p * n); // Chose the middle value. + } + + template + inline RealType skewness(const binomial_distribution& dist) + { + BOOST_MATH_STD_USING // ADL of std functions. + RealType p = dist.success_fraction(); + RealType n = dist.trials(); + return (1 - 2 * p) / sqrt(n * p * (1 - p)); + } + + template + inline RealType kurtosis(const binomial_distribution& dist) + { + RealType p = dist.success_fraction(); + RealType n = dist.trials(); + return 3 - 6 / n + 1 / (n * p * (1 - p)); + } + + template + inline RealType kurtosis_excess(const binomial_distribution& dist) + { + RealType p = dist.success_fraction(); + RealType q = 1 - p; + RealType n = dist.trials(); + return (1 - 6 * p * q) / (n * p * q); + } + + } // namespace math + } // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_MATH_SPECIAL_BINOMIAL_HPP + + diff --git a/include/boost/math/distributions/cauchy.hpp b/include/boost/math/distributions/cauchy.hpp new file mode 100644 index 000000000..ca0b0a3bc --- /dev/null +++ b/include/boost/math/distributions/cauchy.hpp @@ -0,0 +1,347 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_CAUCHY_HPP +#define BOOST_STATS_CAUCHY_HPP + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +#include +#include +#include +#include +#include + +#include + +namespace boost{ namespace math +{ + +template +class cauchy_distribution; + +namespace detail +{ + +template +RealType cdf_imp(const cauchy_distribution& dist, const RealType& x, bool complement) +{ + // + // This calculates the cdf of the Cauchy distribution and/or its complement. + // + // The usual formula for the Cauchy cdf is: + // + // cdf = 0.5 + atan(x)/pi + // + // But that suffers from cancellation error as x -> -INF. + // + // Recall that for x < 0: + // + // atan(x) = -pi/2 - atan(1/x) + // + // Substituting into the above we get: + // + // CDF = -atan(1/x) ; x < 0 + // + // So the proceedure is to calculate the cdf for -fabs(x) + // using the above formula, and then subtract from 1 when required + // to get the result. + // + BOOST_MATH_STD_USING // for ADL of std functions + static const char* function = "boost::math::cdf(cauchy<%1%>&, %1%)"; + RealType result; + RealType location = dist.location(); + RealType scale = dist.scale(); + if(false == detail::check_location(function, location, &result, Policy())) + { + return result; + } + if(false == detail::check_scale(function, scale, &result, Policy())) + { + return result; + } + if(std::numeric_limits::has_infinity && x == std::numeric_limits::infinity()) + { // cdf +infinity is unity. + return static_cast((complement) ? 0 : 1); + } + if(std::numeric_limits::has_infinity && x == -std::numeric_limits::infinity()) + { // cdf -infinity is zero. + return static_cast((complement) ? 1 : 0); + } + if(false == detail::check_x(function, x, &result, Policy())) + { // Catches x == NaN + return result; + } + RealType mx = -fabs((x - location) / scale); // scale is > 0 + if(mx > -tools::epsilon() / 8) + { // special case first: x extremely close to location. + return 0.5; + } + result = -atan(1 / mx) / constants::pi(); + return (((x > location) != complement) ? 1 - result : result); +} // cdf + +template +RealType quantile_imp( + const cauchy_distribution& dist, + const RealType& p, + bool complement) +{ + // This routine implements the quantile for the Cauchy distribution, + // the value p may be the probability, or its complement if complement=true. + // + // The procedure first performs argument reduction on p to avoid error + // when calculating the tangent, then calulates the distance from the + // mid-point of the distribution. This is either added or subtracted + // from the location parameter depending on whether `complement` is true. + // + static const char* function = "boost::math::quantile(cauchy<%1%>&, %1%)"; + BOOST_MATH_STD_USING // for ADL of std functions + + RealType result; + RealType location = dist.location(); + RealType scale = dist.scale(); + if(false == detail::check_location(function, location, &result, Policy())) + { + return result; + } + if(false == detail::check_scale(function, scale, &result, Policy())) + { + return result; + } + if(false == detail::check_probability(function, p, &result, Policy())) + { + return result; + } + // Special cases: + if(p == 1) + { + return (complement ? -1 : 1) * policies::raise_overflow_error(function, 0, Policy()); + } + if(p == 0) + { + return (complement ? 1 : -1) * policies::raise_overflow_error(function, 0, Policy()); + } + + RealType P = p - floor(p); // argument reduction of p: + if(P > 0.5) + { + P = P - 1; + } + if(P == 0.5) // special case: + { + return location; + } + result = -scale / tan(constants::pi() * P); + return complement ? location - result : location + result; +} // quantile + +} // namespace detail + +template > +class cauchy_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + cauchy_distribution(RealType location = 0, RealType scale = 1) + : m_a(location), m_hg(scale) + { + static const char* function = "boost::math::cauchy_distribution<%1%>::cauchy_distribution"; + RealType result; + detail::check_location(function, location, &result, Policy()); + detail::check_scale(function, scale, &result, Policy()); + } // cauchy_distribution + + RealType location()const + { + return m_a; + } + RealType scale()const + { + return m_hg; + } + +private: + RealType m_a; // The location, this is the median of the distribution. + RealType m_hg; // The scale )or shape), this is the half width at half height. +}; + +typedef cauchy_distribution cauchy; + +template +inline const std::pair range(const cauchy_distribution&) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); // - to + infinity. +} + +template +inline const std::pair support(const cauchy_distribution& ) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(-tools::max_value(), tools::max_value()); // - to + infinity. +} + +template +inline RealType pdf(const cauchy_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::pdf(cauchy<%1%>&, %1%)"; + RealType result; + RealType location = dist.location(); + RealType scale = dist.scale(); + if(false == detail::check_scale("boost::math::pdf(cauchy<%1%>&, %1%)", scale, &result, Policy())) + { + return result; + } + if(false == detail::check_location("boost::math::pdf(cauchy<%1%>&, %1%)", location, &result, Policy())) + { + return result; + } + if((boost::math::isinf)(x)) + { + return 0; // pdf + and - infinity is zero. + } + // These produce MSVC 4127 warnings, so the above used instead. + //if(std::numeric_limits::has_infinity && abs(x) == std::numeric_limits::infinity()) + //{ // pdf + and - infinity is zero. + // return 0; + //} + + if(false == detail::check_x(function, x, &result, Policy())) + { // Catches x = NaN + return result; + } + + RealType xs = (x - location) / scale; + result = 1 / (constants::pi() * scale * (1 + xs * xs)); + return result; +} // pdf + +template +inline RealType cdf(const cauchy_distribution& dist, const RealType& x) +{ + return detail::cdf_imp(dist, x, false); +} // cdf + +template +inline RealType quantile(const cauchy_distribution& dist, const RealType& p) +{ + return detail::quantile_imp(dist, p, false); +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + return detail::cdf_imp(c.dist, c.param, true); +} // cdf complement + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + return detail::quantile_imp(c.dist, c.param, true); +} // quantile complement + +template +inline RealType mean(const cauchy_distribution&) +{ // There is no mean: + typedef typename Policy::assert_undefined_type assert_type; + BOOST_STATIC_ASSERT(assert_type::value == 0); + + return policies::raise_domain_error( + "boost::math::mean(cauchy<%1%>&)", + "The Cauchy distribution does not have a mean: " + "the only possible return value is %1%.", + std::numeric_limits::quiet_NaN(), Policy()); +} + +template +inline RealType variance(const cauchy_distribution& /*dist*/) +{ + // There is no variance: + typedef typename Policy::assert_undefined_type assert_type; + BOOST_STATIC_ASSERT(assert_type::value == 0); + + return policies::raise_domain_error( + "boost::math::variance(cauchy<%1%>&)", + "The Cauchy distribution does not have a variance: " + "the only possible return value is %1%.", + std::numeric_limits::quiet_NaN(), Policy()); +} + +template +inline RealType mode(const cauchy_distribution& dist) +{ + return dist.location(); +} + +template +inline RealType median(const cauchy_distribution& dist) +{ + return dist.location(); +} +template +inline RealType skewness(const cauchy_distribution& /*dist*/) +{ + // There is no skewness: + typedef typename Policy::assert_undefined_type assert_type; + BOOST_STATIC_ASSERT(assert_type::value == 0); + + return policies::raise_domain_error( + "boost::math::skewness(cauchy<%1%>&)", + "The Cauchy distribution does not have a skewness: " + "the only possible return value is %1%.", + std::numeric_limits::quiet_NaN(), Policy()); // infinity? +} + +template +inline RealType kurtosis(const cauchy_distribution& /*dist*/) +{ + // There is no kurtosis: + typedef typename Policy::assert_undefined_type assert_type; + BOOST_STATIC_ASSERT(assert_type::value == 0); + + return policies::raise_domain_error( + "boost::math::kurtosis(cauchy<%1%>&)", + "The Cauchy distribution does not have a kurtosis: " + "the only possible return value is %1%.", + std::numeric_limits::quiet_NaN(), Policy()); +} + +template +inline RealType kurtosis_excess(const cauchy_distribution& /*dist*/) +{ + // There is no kurtosis excess: + typedef typename Policy::assert_undefined_type assert_type; + BOOST_STATIC_ASSERT(assert_type::value == 0); + + return policies::raise_domain_error( + "boost::math::kurtosis_excess(cauchy<%1%>&)", + "The Cauchy distribution does not have a kurtosis: " + "the only possible return value is %1%.", + std::numeric_limits::quiet_NaN(), Policy()); +} + +} // namespace math +} // namespace boost + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_CAUCHY_HPP diff --git a/include/boost/math/distributions/chi_squared.hpp b/include/boost/math/distributions/chi_squared.hpp new file mode 100644 index 000000000..cbed73d24 --- /dev/null +++ b/include/boost/math/distributions/chi_squared.hpp @@ -0,0 +1,326 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP +#define BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP + +#include +#include // for incomplete beta. +#include // complements +#include // error checks +#include + +#include + +namespace boost{ namespace math{ + +template > +class chi_squared_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + chi_squared_distribution(RealType i) : m_df(i) + { + RealType result; + detail::check_df( + "boost::math::chi_squared_distribution<%1%>::chi_squared_distribution", m_df, &result, Policy()); + } // chi_squared_distribution + + RealType degrees_of_freedom()const + { + return m_df; + } + + // Parameter estimation: + static RealType find_degrees_of_freedom( + RealType difference_from_variance, + RealType alpha, + RealType beta, + RealType variance, + RealType hint = 100); + +private: + // + // Data member: + // + RealType m_df; // degrees of freedom are a real number. +}; // class chi_squared_distribution + +typedef chi_squared_distribution chi_squared; + +template +inline const std::pair range(const chi_squared_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, max_value()); // 0 to + infinity. +} + +template +inline const std::pair support(const chi_squared_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(0, tools::max_value()); // 0 to + infinity. +} + +template +RealType pdf(const chi_squared_distribution& dist, const RealType& chi_square) +{ + BOOST_MATH_STD_USING // for ADL of std functions + RealType degrees_of_freedom = dist.degrees_of_freedom(); + // Error check: + RealType error_result; + + static const char* function = "boost::math::pdf(const chi_squared_distribution<%1%>&, %1%)"; + + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy())) + return error_result; + + if((chi_square < 0) || !(boost::math::isfinite)(chi_square)) + { + return policies::raise_domain_error( + function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy()); + } + + if(chi_square == 0) + { + // Handle special cases: + if(degrees_of_freedom < 2) + { + return policies::raise_overflow_error( + function, 0, Policy()); + } + else if(degrees_of_freedom == 2) + { + return 0.5f; + } + else + { + return 0; + } + } + + return gamma_p_derivative(degrees_of_freedom / 2, chi_square / 2, Policy()) / 2; +} // pdf + +template +inline RealType cdf(const chi_squared_distribution& dist, const RealType& chi_square) +{ + RealType degrees_of_freedom = dist.degrees_of_freedom(); + // Error check: + RealType error_result; + static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)"; + + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy())) + return error_result; + + if((chi_square < 0) || !(boost::math::isfinite)(chi_square)) + { + return policies::raise_domain_error( + function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy()); + } + + return boost::math::gamma_p(degrees_of_freedom / 2, chi_square / 2, Policy()); +} // cdf + +template +inline RealType quantile(const chi_squared_distribution& dist, const RealType& p) +{ + RealType degrees_of_freedom = dist.degrees_of_freedom(); + static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)"; + // Error check: + RealType error_result; + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy()) + && detail::check_probability( + function, p, &error_result, Policy())) + return error_result; + + return 2 * boost::math::gamma_p_inv(degrees_of_freedom / 2, p, Policy()); +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + RealType const& degrees_of_freedom = c.dist.degrees_of_freedom(); + RealType const& chi_square = c.param; + static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)"; + // Error check: + RealType error_result; + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy())) + return error_result; + + if((chi_square < 0) || !(boost::math::isfinite)(chi_square)) + { + return policies::raise_domain_error( + function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy()); + } + + return boost::math::gamma_q(degrees_of_freedom / 2, chi_square / 2, Policy()); +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + RealType const& degrees_of_freedom = c.dist.degrees_of_freedom(); + RealType const& q = c.param; + static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)"; + // Error check: + RealType error_result; + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy()) + && detail::check_probability( + function, q, &error_result, Policy())) + return error_result; + + return 2 * boost::math::gamma_q_inv(degrees_of_freedom / 2, q, Policy()); +} + +template +inline RealType mean(const chi_squared_distribution& dist) +{ // Mean of Chi-Squared distribution = v. + return dist.degrees_of_freedom(); +} // mean + +template +inline RealType variance(const chi_squared_distribution& dist) +{ // Variance of Chi-Squared distribution = 2v. + return 2 * dist.degrees_of_freedom(); +} // variance + +template +inline RealType mode(const chi_squared_distribution& dist) +{ + RealType df = dist.degrees_of_freedom(); + static const char* function = "boost::math::mode(const chi_squared_distribution<%1%>&)"; + if(df <= 2) + return policies::raise_domain_error( + function, + "The Chi-Squared distribution only has a mode for degrees of freedom >= 2, but got degrees of freedom = %1%.", + df, Policy()); + return df - 2; +} + +//template +//inline RealType median(const chi_squared_distribution& dist) +//{ // Median is given by Quantile[dist, 1/2] +// RealType df = dist.degrees_of_freedom(); +// if(df <= 1) +// return tools::domain_error( +// BOOST_CURRENT_FUNCTION, +// "The Chi-Squared distribution only has a mode for degrees of freedom >= 2, but got degrees of freedom = %1%.", +// df); +// return df - RealType(2)/3; +//} +// Now implemented via quantile(half) in derived accessors. + +template +inline RealType skewness(const chi_squared_distribution& dist) +{ + BOOST_MATH_STD_USING // For ADL + RealType df = dist.degrees_of_freedom(); + return sqrt (8 / df); // == 2 * sqrt(2 / df); +} + +template +inline RealType kurtosis(const chi_squared_distribution& dist) +{ + RealType df = dist.degrees_of_freedom(); + return 3 + 12 / df; +} + +template +inline RealType kurtosis_excess(const chi_squared_distribution& dist) +{ + RealType df = dist.degrees_of_freedom(); + return 12 / df; +} + +// +// Parameter estimation comes last: +// +namespace detail +{ + +template +struct df_estimator +{ + df_estimator(RealType a, RealType b, RealType variance, RealType delta) + : alpha(a), beta(b), ratio(delta/variance) {} + + RealType operator()(const RealType& df) + { + if(df <= tools::min_value()) + return 1; + chi_squared_distribution cs(df); + + RealType result; + if(ratio > 0) + { + RealType r = 1 + ratio; + result = cdf(cs, quantile(complement(cs, alpha)) / r) - beta; + } + else + { + RealType r = 1 + ratio; + result = cdf(complement(cs, quantile(cs, alpha) / r)) - beta; + } + return result; + } +private: + RealType alpha, beta, ratio; +}; + +} // namespace detail + +template +RealType chi_squared_distribution::find_degrees_of_freedom( + RealType difference_from_variance, + RealType alpha, + RealType beta, + RealType variance, + RealType hint) +{ + static const char* function = "boost::math::chi_squared_distribution<%1%>::find_degrees_of_freedom(%1%,%1%,%1%,%1%,%1%)"; + // Check for domain errors: + RealType error_result; + if(false == detail::check_probability( + function, alpha, &error_result, Policy()) + && detail::check_probability(function, beta, &error_result, Policy())) + return error_result; + + if(hint <= 0) + hint = 1; + + detail::df_estimator f(alpha, beta, variance, difference_from_variance); + tools::eps_tolerance tol(policies::digits()); + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + std::pair r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy()); + RealType result = r.first + (r.second - r.first) / 2; + if(max_iter == policies::get_max_root_iterations()) + { + policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" + " either there is no answer to how many degrees of freedom are required" + " or the answer is infinite. Current best guess is %1%", result, Policy()); + } + return result; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP diff --git a/include/boost/math/distributions/complement.hpp b/include/boost/math/distributions/complement.hpp new file mode 100644 index 000000000..7eb08753a --- /dev/null +++ b/include/boost/math/distributions/complement.hpp @@ -0,0 +1,195 @@ +// (C) Copyright John Maddock 2006. +// (C) Copyright Paul A. Bristow 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_COMPLEMENT_HPP +#define BOOST_STATS_COMPLEMENT_HPP + +// +// This code really defines our own tuple type. +// It would be nice to reuse std::tr1::tuple +// while retaining our own type safety, but it's +// not clear if that's possible. In any case this +// code is *very* lightweight. +// +namespace boost{ namespace math{ + +template +struct complemented2_type +{ + complemented2_type( + const Dist& d, + const RealType& p1) + : dist(d), + param(p1) {} + + const Dist& dist; + const RealType& param; + +private: + complemented2_type& operator=(const complemented2_type&); +}; + +template +struct complemented3_type +{ + complemented3_type( + const Dist& d, + const RealType1& p1, + const RealType2& p2) + : dist(d), + param1(p1), + param2(p2) {} + + const Dist& dist; + const RealType1& param1; + const RealType2& param2; +private: + complemented3_type& operator=(const complemented3_type&); +}; + +template +struct complemented4_type +{ + complemented4_type( + const Dist& d, + const RealType1& p1, + const RealType2& p2, + const RealType3& p3) + : dist(d), + param1(p1), + param2(p2), + param3(p3) {} + + const Dist& dist; + const RealType1& param1; + const RealType2& param2; + const RealType3& param3; +private: + complemented4_type& operator=(const complemented4_type&); +}; + +template +struct complemented5_type +{ + complemented5_type( + const Dist& d, + const RealType1& p1, + const RealType2& p2, + const RealType3& p3, + const RealType4& p4) + : dist(d), + param1(p1), + param2(p2), + param3(p3), + param4(p4) {} + + const Dist& dist; + const RealType1& param1; + const RealType2& param2; + const RealType3& param3; + const RealType4& param4; +private: + complemented5_type& operator=(const complemented5_type&); +}; + +template +struct complemented6_type +{ + complemented6_type( + const Dist& d, + const RealType1& p1, + const RealType2& p2, + const RealType3& p3, + const RealType4& p4, + const RealType5& p5) + : dist(d), + param1(p1), + param2(p2), + param3(p3), + param4(p4), + param5(p5) {} + + const Dist& dist; + const RealType1& param1; + const RealType2& param2; + const RealType3& param3; + const RealType4& param4; + const RealType5& param5; +private: + complemented6_type& operator=(const complemented6_type&); +}; + +template +struct complemented7_type +{ + complemented7_type( + const Dist& d, + const RealType1& p1, + const RealType2& p2, + const RealType3& p3, + const RealType4& p4, + const RealType5& p5, + const RealType6& p6) + : dist(d), + param1(p1), + param2(p2), + param3(p3), + param4(p4), + param5(p5), + param6(p6) {} + + const Dist& dist; + const RealType1& param1; + const RealType2& param2; + const RealType3& param3; + const RealType4& param4; + const RealType5& param5; + const RealType6& param6; +private: + complemented7_type& operator=(const complemented7_type&); +}; + +template +inline complemented2_type complement(const Dist& d, const RealType& r) +{ + return complemented2_type(d, r); +} + +template +inline complemented3_type complement(const Dist& d, const RealType1& r1, const RealType2& r2) +{ + return complemented3_type(d, r1, r2); +} + +template +inline complemented4_type complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3) +{ + return complemented4_type(d, r1, r2, r3); +} + +template +inline complemented5_type complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4) +{ + return complemented5_type(d, r1, r2, r3, r4); +} + +template +inline complemented6_type complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4, const RealType5& r5) +{ + return complemented6_type(d, r1, r2, r3, r4, r5); +} + +template +inline complemented7_type complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4, const RealType5& r5, const RealType6& r6) +{ + return complemented7_type(d, r1, r2, r3, r4, r5, r6); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_STATS_COMPLEMENT_HPP + diff --git a/include/boost/math/distributions/detail/common_error_handling.hpp b/include/boost/math/distributions/detail/common_error_handling.hpp new file mode 100644 index 000000000..d13776c6d --- /dev/null +++ b/include/boost/math/distributions/detail/common_error_handling.hpp @@ -0,0 +1,103 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP +#define BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP + +#include +#include +// using boost::math::isfinite; + +namespace boost{ namespace math{ namespace detail +{ + +template +inline bool check_probability(const char* function, RealType const& prob, RealType* result, const Policy& pol) +{ + if((prob < 0) || (prob > 1) || !(boost::math::isfinite)(prob)) + { + *result = policies::raise_domain_error( + function, + "Probability argument is %1%, but must be >= 0 and <= 1 !", prob, pol); + return false; + } + return true; +} + +template +inline bool check_df(const char* function, RealType const& df, RealType* result, const Policy& pol) +{ + if((df <= 0) || !(boost::math::isfinite)(df)) + { + *result = policies::raise_domain_error( + function, + "Degrees of freedom argument is %1%, but must be > 0 !", df, pol); + return false; + } + return true; +} + +template +inline bool check_scale( + const char* function, + RealType scale, + RealType* result, + const Policy& pol) +{ + if((scale <= 0) || !(boost::math::isfinite)(scale)) + { // Assume scale == 0 is NOT valid for any distribution. + *result = policies::raise_domain_error( + function, + "Scale parameter is %1%, but must be > 0 !", scale, pol); + return false; + } + return true; +} + +template +inline bool check_location( + const char* function, + RealType location, + RealType* result, + const Policy& pol) +{ + if(!(boost::math::isfinite)(location)) + { + *result = policies::raise_domain_error( + function, + "Location parameter is %1%, but must be finite!", location, pol); + return false; + } + return true; +} + +template +inline bool check_x( + const char* function, + RealType x, + RealType* result, + const Policy& pol) +{ + if(!(boost::math::isfinite)(x)) + { + *result = policies::raise_domain_error( + function, + "Random variate x is %1%, but must be finite!", x, pol); + return false; + } + return true; + // Note that this test catches both infinity and NaN. + // Some special cases permit x to be infinite, so these must be tested 1st, + // leaving this test to catch any NaNs. see Normal and cauchy for example. +} + +} // namespace detail +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP diff --git a/include/boost/math/distributions/detail/derived_accessors.hpp b/include/boost/math/distributions/detail/derived_accessors.hpp new file mode 100644 index 000000000..00f5a9325 --- /dev/null +++ b/include/boost/math/distributions/detail/derived_accessors.hpp @@ -0,0 +1,163 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_DERIVED_HPP +#define BOOST_STATS_DERIVED_HPP + +// This file implements various common properties of distributions +// that can be implemented in terms of other properties: +// variance OR standard deviation (see note below), +// hazard, cumulative hazard (chf), coefficient_of_variation. +// +// Note that while both variance and standard_deviation are provided +// here, each distribution MUST SPECIALIZE AT LEAST ONE OF THESE +// otherwise these two versions will just call each other over and over +// until stack space runs out ... + +// Of course there may be more efficient means of implementing these +// that are specific to a particular distribution, but these generic +// versions give these properties "for free" with most distributions. +// +// In order to make use of this header, it must be included AT THE END +// of the distribution header, AFTER the distribution and its core +// property accessors have been defined: this is so that compilers +// that implement 2-phase lookup and early-type-checking of templates +// can find the definitions refered to herein. +// + +#include +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4723) // potential divide by 0 +// Suppressing spurious warning in coefficient_of_variation +#endif + +namespace boost{ namespace math{ + +template +typename Distribution::value_type variance(const Distribution& dist); + +template +inline typename Distribution::value_type standard_deviation(const Distribution& dist) +{ + BOOST_MATH_STD_USING // ADL of sqrt. + return sqrt(variance(dist)); +} + +template +inline typename Distribution::value_type variance(const Distribution& dist) +{ + typename Distribution::value_type result = standard_deviation(dist); + return result * result; +} + +template +inline typename Distribution::value_type hazard(const Distribution& dist, const RealType& x) +{ // hazard function + // http://www.itl.nist.gov/div898/handbook/eda/section3/eda362.htm#HAZ + typedef typename Distribution::value_type value_type; + typedef typename Distribution::policy_type policy_type; + value_type p = cdf(complement(dist, x)); + value_type d = pdf(dist, x); + if(d > p * tools::max_value()) + return policies::raise_overflow_error( + "boost::math::hazard(const Distribution&, %1%)", 0, policy_type()); + if(d == 0) + { + // This protects against 0/0, but is it the right thing to do? + return 0; + } + return d / p; +} + +template +inline typename Distribution::value_type chf(const Distribution& dist, const RealType& x) +{ // cumulative hazard function. + // http://www.itl.nist.gov/div898/handbook/eda/section3/eda362.htm#HAZ + BOOST_MATH_STD_USING + return -log(cdf(complement(dist, x))); +} + +template +inline typename Distribution::value_type coefficient_of_variation(const Distribution& dist) +{ + typedef typename Distribution::value_type value_type; + typedef typename Distribution::policy_type policy_type; + + using std::abs; + + value_type m = mean(dist); + value_type d = standard_deviation(dist); + if((abs(m) < 1) && (d > abs(m) * tools::max_value())) + { // Checks too that m is not zero, + return policies::raise_overflow_error("boost::math::coefficient_of_variation(const Distribution&, %1%)", 0, policy_type()); + } + return d / m; // so MSVC warning on zerodivide is spurious, and suppressed. +} +// +// Next follow overloads of some of the standard accessors with mixed +// argument types. We just use a typecast to forward on to the "real" +// implementation with all arguments of the same type: +// +template +inline typename Distribution::value_type pdf(const Distribution& dist, const RealType& x) +{ + typedef typename Distribution::value_type value_type; + return pdf(dist, static_cast(x)); +} +template +inline typename Distribution::value_type cdf(const Distribution& dist, const RealType& x) +{ + typedef typename Distribution::value_type value_type; + return cdf(dist, static_cast(x)); +} +template +inline typename Distribution::value_type quantile(const Distribution& dist, const RealType& x) +{ + typedef typename Distribution::value_type value_type; + return quantile(dist, static_cast(x)); +} +/* +template +inline typename Distribution::value_type chf(const Distribution& dist, const RealType& x) +{ + typedef typename Distribution::value_type value_type; + return chf(dist, static_cast(x)); +} +*/ +template +inline typename Distribution::value_type cdf(const complemented2_type& c) +{ + typedef typename Distribution::value_type value_type; + return cdf(complement(c.dist, static_cast(c.param))); +} + +template +inline typename Distribution::value_type quantile(const complemented2_type& c) +{ + typedef typename Distribution::value_type value_type; + return quantile(complement(c.dist, static_cast(c.param))); +} + +template +inline typename Dist::value_type median(const Dist& d) +{ // median - default definition for those distributions for which a + // simple closed form is not known, + // and for which a domain_error and/or NaN generating function is NOT defined. + typedef typename Dist::value_type value_type; + return quantile(d, static_cast(0.5f)); +} + +} // namespace math +} // namespace boost + + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // BOOST_STATS_DERIVED_HPP diff --git a/include/boost/math/distributions/detail/inv_discrete_quantile.hpp b/include/boost/math/distributions/detail/inv_discrete_quantile.hpp new file mode 100644 index 000000000..202602791 --- /dev/null +++ b/include/boost/math/distributions/detail/inv_discrete_quantile.hpp @@ -0,0 +1,481 @@ +// Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE +#define BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE + +#include + +namespace boost{ namespace math{ namespace detail{ + +// +// Functor for root finding algorithm: +// +template +struct distribution_quantile_finder +{ + typedef typename Dist::value_type value_type; + typedef typename Dist::policy_type policy_type; + + distribution_quantile_finder(const Dist d, value_type p, value_type q) + : dist(d), target(p < q ? p : q), comp(p < q ? false : true) {} + + value_type operator()(value_type const& x) + { + return comp ? target - cdf(complement(dist, x)) : cdf(dist, x) - target; + } + +private: + Dist dist; + value_type target; + bool comp; +}; +// +// The purpose of adjust_bounds, is to toggle the last bit of the +// range so that both ends round to the same integer, if possible. +// If they do both round the same then we terminate the search +// for the root *very* quickly when finding an integer result. +// At the point that this function is called we know that "a" is +// below the root and "b" above it, so this change can not result +// in the root no longer being bracketed. +// +template +void adjust_bounds(Real& /* a */, Real& /* b */, Tol const& /* tol */){} + +template +void adjust_bounds(Real& /* a */, Real& b, tools::equal_floor const& /* tol */) +{ + BOOST_MATH_STD_USING + b -= tools::epsilon() * b; +} + +template +void adjust_bounds(Real& a, Real& /* b */, tools::equal_ceil const& /* tol */) +{ + BOOST_MATH_STD_USING + a += tools::epsilon() * a; +} + +template +void adjust_bounds(Real& a, Real& b, tools::equal_nearest_integer const& /* tol */) +{ + BOOST_MATH_STD_USING + a += tools::epsilon() * a; + b -= tools::epsilon() * b; +} +// +// This is where all the work is done: +// +template +typename Dist::value_type + do_inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + typename Dist::value_type guess, + const typename Dist::value_type& multiplier, + typename Dist::value_type adder, + const Tolerance& tol, + boost::uintmax_t& max_iter) +{ + typedef typename Dist::value_type value_type; + typedef typename Dist::policy_type policy_type; + + static const char* function = "boost::math::do_inverse_discrete_quantile<%1%>"; + + BOOST_MATH_STD_USING + + distribution_quantile_finder f(dist, p, q); + // + // Max bounds of the distribution: + // + value_type min_bound, max_bound; + std::tr1::tie(min_bound, max_bound) = support(dist); + + if(guess > max_bound) + guess = max_bound; + if(guess < min_bound) + guess = min_bound; + + value_type fa = f(guess); + boost::uintmax_t count = max_iter - 1; + value_type fb(fa), a(guess), b =0; // Compiler warning C4701: potentially uninitialized local variable 'b' used + + if(fa == 0) + return guess; + + // + // For small expected results, just use a linear search: + // + if(guess < 10) + { + b = a; + while((a < 10) && (fa * fb >= 0)) + { + if(fb <= 0) + { + a = b; + b = a + 1; + if(b > max_bound) + b = max_bound; + fb = f(b); + --count; + if(fb == 0) + return b; + } + else + { + b = a; + a = (std::max)(b - 1, value_type(0)); + if(a < min_bound) + a = min_bound; + fa = f(a); + --count; + if(fa == 0) + return a; + } + } + } + // + // Try and bracket using a couple of additions first, + // we're assuming that "guess" is likely to be accurate + // to the nearest int or so: + // + else if(adder != 0) + { + // + // If we're looking for a large result, then bump "adder" up + // by a bit to increase our chances of bracketing the root: + // + //adder = (std::max)(adder, 0.001f * guess); + if(fa < 0) + { + b = a + adder; + if(b > max_bound) + b = max_bound; + } + else + { + b = (std::max)(a - adder, value_type(0)); + if(b < min_bound) + b = min_bound; + } + fb = f(b); + --count; + if(fb == 0) + return b; + if(count && (fa * fb >= 0)) + { + // + // We didn't bracket the root, try + // once more: + // + a = b; + fa = fb; + if(fa < 0) + { + b = a + adder; + if(b > max_bound) + b = max_bound; + } + else + { + b = (std::max)(a - adder, value_type(0)); + if(b < min_bound) + b = min_bound; + } + fb = f(b); + --count; + } + if(a > b) + { + using std::swap; + swap(a, b); + swap(fa, fb); + } + } + // + // If the root hasn't been bracketed yet, try again + // using the multiplier this time: + // + if((boost::math::sign)(fb) == (boost::math::sign)(fa)) + { + if(fa < 0) + { + // + // Zero is to the right of x2, so walk upwards + // until we find it: + // + while((boost::math::sign)(fb) == (boost::math::sign)(fa)) + { + if(count == 0) + policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, policy_type()); + a = b; + fa = fb; + b *= multiplier; + if(b > max_bound) + b = max_bound; + fb = f(b); + --count; + BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count); + } + } + else + { + // + // Zero is to the left of a, so walk downwards + // until we find it: + // + while((boost::math::sign)(fb) == (boost::math::sign)(fa)) + { + if(fabs(a) < tools::min_value()) + { + // Escape route just in case the answer is zero! + max_iter -= count; + max_iter += 1; + return 0; + } + if(count == 0) + policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, policy_type()); + b = a; + fb = fa; + a /= multiplier; + if(a < min_bound) + a = min_bound; + fa = f(a); + --count; + BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count); + } + } + } + max_iter -= count; + if(fa == 0) + return a; + if(fb == 0) + return b; + // + // Adjust bounds so that if we're looking for an integer + // result, then both ends round the same way: + // + adjust_bounds(a, b, tol); + // + // We don't want zero or denorm lower bounds: + // + if(a < tools::min_value()) + a = tools::min_value(); + // + // Go ahead and find the root: + // + std::pair r = toms748_solve(f, a, b, fa, fb, tol, count, policy_type()); + max_iter += count; + BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count); + return (r.first + r.second) / 2; +} +// +// Now finally are the public API functions. +// There is one overload for each policy, +// each one is responsible for selecting the correct +// termination condition, and rounding the result +// to an int where required. +// +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + if(p <= pdf(dist, 0)) + return 0; + return do_inverse_discrete_quantile( + dist, + p, + q, + guess, + multiplier, + adder, + tools::eps_tolerance(policies::digits()), + max_iter); +} + +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + typedef typename Dist::value_type value_type; + BOOST_MATH_STD_USING + if(p <= pdf(dist, 0)) + return 0; + // + // What happens next depends on whether we're looking for an + // upper or lower quantile: + // + if(p < 0.5f) + return floor(do_inverse_discrete_quantile( + dist, + p, + q, + (guess < 1 ? value_type(1) : floor(guess)), + multiplier, + adder, + tools::equal_floor(), + max_iter)); + // else: + return ceil(do_inverse_discrete_quantile( + dist, + p, + q, + ceil(guess), + multiplier, + adder, + tools::equal_ceil(), + max_iter)); +} + +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + typedef typename Dist::value_type value_type; + BOOST_MATH_STD_USING + if(p <= pdf(dist, 0)) + return 0; + // + // What happens next depends on whether we're looking for an + // upper or lower quantile: + // + if(p < 0.5f) + return ceil(do_inverse_discrete_quantile( + dist, + p, + q, + ceil(guess), + multiplier, + adder, + tools::equal_ceil(), + max_iter)); + // else: + return floor(do_inverse_discrete_quantile( + dist, + p, + q, + (guess < 1 ? value_type(1) : floor(guess)), + multiplier, + adder, + tools::equal_floor(), + max_iter)); +} + +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + typedef typename Dist::value_type value_type; + BOOST_MATH_STD_USING + if(p <= pdf(dist, 0)) + return 0; + return floor(do_inverse_discrete_quantile( + dist, + p, + q, + (guess < 1 ? value_type(1) : floor(guess)), + multiplier, + adder, + tools::equal_floor(), + max_iter)); +} + +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + BOOST_MATH_STD_USING + if(p <= pdf(dist, 0)) + return 0; + return ceil(do_inverse_discrete_quantile( + dist, + p, + q, + ceil(guess), + multiplier, + adder, + tools::equal_ceil(), + max_iter)); +} + +template +inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& q, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter) +{ + typedef typename Dist::value_type value_type; + BOOST_MATH_STD_USING + if(p <= pdf(dist, 0)) + return 0; + // + // Note that we adjust the guess to the nearest half-integer: + // this increase the chances that we will bracket the root + // with two results that both round to the same integer quickly. + // + return floor(do_inverse_discrete_quantile( + dist, + p, + q, + (guess < 0.5f ? value_type(1.5f) : floor(guess + 0.5f) + 0.5f), + multiplier, + adder, + tools::equal_nearest_integer(), + max_iter) + 0.5f); +} + +}}} // namespaces + +#endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE + + diff --git a/include/boost/math/distributions/exponential.hpp b/include/boost/math/distributions/exponential.hpp new file mode 100644 index 000000000..669636c37 --- /dev/null +++ b/include/boost/math/distributions/exponential.hpp @@ -0,0 +1,259 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_EXPONENTIAL_HPP +#define BOOST_STATS_EXPONENTIAL_HPP + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code (return after domain_error throw). +#endif + +#include + +namespace boost{ namespace math{ + +namespace detail{ +// +// Error check: +// +template +inline bool verify_lambda(const char* function, RealType l, RealType* presult, const Policy& pol) +{ + if(l <= 0) + { + *presult = policies::raise_domain_error( + function, + "The scale parameter \"lambda\" must be > 0, but was: %1%.", l, pol); + return false; + } + return true; +} + +template +inline bool verify_exp_x(const char* function, RealType x, RealType* presult, const Policy& pol) +{ + if(x < 0) + { + *presult = policies::raise_domain_error( + function, + "The random variable must be >= 0, but was: %1%.", x, pol); + return false; + } + return true; +} + +} // namespace detail + +template > +class exponential_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + exponential_distribution(RealType lambda = 1) + : m_lambda(lambda) + { + RealType err; + detail::verify_lambda("boost::math::exponential_distribution<%1%>::exponential_distribution", lambda, &err, Policy()); + } // exponential_distribution + + RealType lambda()const { return m_lambda; } + +private: + RealType m_lambda; +}; + +typedef exponential_distribution exponential; + +template +inline const std::pair range(const exponential_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(static_cast(0), max_value()); +} + +template +inline const std::pair support(const exponential_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline RealType pdf(const exponential_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::pdf(const exponential_distribution<%1%>&, %1%)"; + + RealType lambda = dist.lambda(); + RealType result; + if(0 == detail::verify_lambda(function, lambda, &result, Policy())) + return result; + if(0 == detail::verify_exp_x(function, x, &result, Policy())) + return result; + result = lambda * exp(-lambda * x); + return result; +} // pdf + +template +inline RealType cdf(const exponential_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const exponential_distribution<%1%>&, %1%)"; + + RealType result; + RealType lambda = dist.lambda(); + if(0 == detail::verify_lambda(function, lambda, &result, Policy())) + return result; + if(0 == detail::verify_exp_x(function, x, &result, Policy())) + return result; + result = -boost::math::expm1(-x * lambda, Policy()); + + return result; +} // cdf + +template +inline RealType quantile(const exponential_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const exponential_distribution<%1%>&, %1%)"; + + RealType result; + RealType lambda = dist.lambda(); + if(0 == detail::verify_lambda(function, lambda, &result, Policy())) + return result; + if(0 == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 0) + return 0; + if(p == 1) + return policies::raise_overflow_error(function, 0, Policy()); + + result = -boost::math::log1p(-p, Policy()) / lambda; + return result; +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const exponential_distribution<%1%>&, %1%)"; + + RealType result; + RealType lambda = c.dist.lambda(); + if(0 == detail::verify_lambda(function, lambda, &result, Policy())) + return result; + if(0 == detail::verify_exp_x(function, c.param, &result, Policy())) + return result; + result = exp(-c.param * lambda); + + return result; +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const exponential_distribution<%1%>&, %1%)"; + + RealType result; + RealType lambda = c.dist.lambda(); + if(0 == detail::verify_lambda(function, lambda, &result, Policy())) + return result; + + RealType q = c.param; + if(0 == detail::check_probability(function, q, &result, Policy())) + return result; + + if(q == 1) + return 0; + if(q == 0) + return policies::raise_overflow_error(function, 0, Policy()); + + result = -log(q) / lambda; + return result; +} + +template +inline RealType mean(const exponential_distribution& dist) +{ + RealType result; + RealType lambda = dist.lambda(); + if(0 == detail::verify_lambda("boost::math::mean(const exponential_distribution<%1%>&)", lambda, &result, Policy())) + return result; + return 1 / lambda; +} + +template +inline RealType standard_deviation(const exponential_distribution& dist) +{ + RealType result; + RealType lambda = dist.lambda(); + if(0 == detail::verify_lambda("boost::math::standard_deviation(const exponential_distribution<%1%>&)", lambda, &result, Policy())) + return result; + return 1 / lambda; +} + +template +inline RealType mode(const exponential_distribution& /*dist*/) +{ + return 0; +} + +template +inline RealType median(const exponential_distribution& dist) +{ + using boost::math::constants::ln_two; + return ln_two() / dist.lambda(); // ln(2) / lambda +} + +template +inline RealType skewness(const exponential_distribution& /*dist*/) +{ + return 2; +} + +template +inline RealType kurtosis(const exponential_distribution& /*dist*/) +{ + return 9; +} + +template +inline RealType kurtosis_excess(const exponential_distribution& /*dist*/) +{ + return 6; +} + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_EXPONENTIAL_HPP diff --git a/include/boost/math/distributions/extreme_value.hpp b/include/boost/math/distributions/extreme_value.hpp new file mode 100644 index 000000000..038307181 --- /dev/null +++ b/include/boost/math/distributions/extreme_value.hpp @@ -0,0 +1,260 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_EXTREME_VALUE_HPP +#define BOOST_STATS_EXTREME_VALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +// +// This is the maximum extreme value distribution, see +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366g.htm +// and http://mathworld.wolfram.com/ExtremeValueDistribution.html +// Also known as a Fisher-Tippett distribution, a log-Weibull +// distribution or a Gumbel distribution. + +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code (return after domain_error throw). +#endif + +namespace boost{ namespace math{ + +namespace detail{ +// +// Error check: +// +template +inline bool verify_scale_b(const char* function, RealType b, RealType* presult, const Policy& pol) +{ + if(b <= 0) + { + *presult = policies::raise_domain_error( + function, + "The scale parameter \"b\" must be > 0, but was: %1%.", b, pol); + return false; + } + return true; +} + +} // namespace detail + +template > +class extreme_value_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + extreme_value_distribution(RealType a = 0, RealType b = 1) + : m_a(a), m_b(b) + { + RealType err; + detail::verify_scale_b("boost::math::extreme_value_distribution<%1%>::extreme_value_distribution", b, &err, Policy()); + } // extreme_value_distribution + + RealType location()const { return m_a; } + RealType scale()const { return m_b; } + +private: + RealType m_a, m_b; +}; + +typedef extreme_value_distribution extreme_value; + +template +inline const std::pair range(const extreme_value_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); +} + +template +inline const std::pair support(const extreme_value_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); +} + +template +inline RealType pdf(const extreme_value_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType a = dist.location(); + RealType b = dist.scale(); + RealType result; + if(0 == detail::verify_scale_b("boost::math::pdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy())) + return result; + result = exp((a-x)/b) * exp(-exp((a-x)/b)) / b; + return result; +} // pdf + +template +inline RealType cdf(const extreme_value_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType a = dist.location(); + RealType b = dist.scale(); + RealType result; + if(0 == detail::verify_scale_b("boost::math::cdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy())) + return result; + + result = exp(-exp((a-x)/b)); + + return result; +} // cdf + +template +RealType quantile(const extreme_value_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const extreme_value_distribution<%1%>&, %1%)"; + + RealType a = dist.location(); + RealType b = dist.scale(); + RealType result; + if(0 == detail::verify_scale_b(function, b, &result, Policy())) + return result; + if(0 == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 0) + return -policies::raise_overflow_error(function, 0, Policy()); + if(p == 1) + return policies::raise_overflow_error(function, 0, Policy()); + + result = a - log(-log(p)) * b; + + return result; +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType a = c.dist.location(); + RealType b = c.dist.scale(); + RealType result; + if(0 == detail::verify_scale_b("boost::math::cdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy())) + return result; + + result = -boost::math::expm1(-exp((a-c.param)/b), Policy()); + + return result; +} + +template +RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const extreme_value_distribution<%1%>&, %1%)"; + + RealType a = c.dist.location(); + RealType b = c.dist.scale(); + RealType q = c.param; + RealType result; + if(0 == detail::verify_scale_b(function, b, &result, Policy())) + return result; + if(0 == detail::check_probability(function, q, &result, Policy())) + return result; + + if(q == 0) + return policies::raise_overflow_error(function, 0, Policy()); + if(q == 1) + return -policies::raise_overflow_error(function, 0, Policy()); + + result = a - log(-boost::math::log1p(-q, Policy())) * b; + + return result; +} + +template +inline RealType mean(const extreme_value_distribution& dist) +{ + RealType a = dist.location(); + RealType b = dist.scale(); + RealType result; + if(0 == detail::verify_scale_b("boost::math::mean(const extreme_value_distribution<%1%>&)", b, &result, Policy())) + return result; + return a + constants::euler() * b; +} + +template +inline RealType standard_deviation(const extreme_value_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions. + + RealType b = dist.scale(); + RealType result; + if(0 == detail::verify_scale_b("boost::math::standard_deviation(const extreme_value_distribution<%1%>&)", b, &result, Policy())) + return result; + return constants::pi() * b / sqrt(static_cast(6)); +} + +template +inline RealType mode(const extreme_value_distribution& dist) +{ + return dist.location(); +} + +template +inline RealType median(const extreme_value_distribution& dist) +{ + using constants::ln_ln_two; + return dist.location() - dist.scale() * ln_ln_two(); +} + +template +inline RealType skewness(const extreme_value_distribution& /*dist*/) +{ + // + // This is 12 * sqrt(6) * zeta(3) / pi^3: + // See http://mathworld.wolfram.com/ExtremeValueDistribution.html + // + return static_cast(1.1395470994046486574927930193898461120875997958366L); +} + +template +inline RealType kurtosis(const extreme_value_distribution& /*dist*/) +{ + // See http://mathworld.wolfram.com/ExtremeValueDistribution.html + return RealType(27) / 5; +} + +template +inline RealType kurtosis_excess(const extreme_value_distribution& /*dist*/) +{ + // See http://mathworld.wolfram.com/ExtremeValueDistribution.html + return RealType(12) / 5; +} + + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_EXTREME_VALUE_HPP diff --git a/include/boost/math/distributions/find_location.hpp b/include/boost/math/distributions/find_location.hpp new file mode 100644 index 000000000..654e8afa4 --- /dev/null +++ b/include/boost/math/distributions/find_location.hpp @@ -0,0 +1,144 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_FIND_LOCATION_HPP +#define BOOST_STATS_FIND_LOCATION_HPP + +#include // for all distribution signatures. +#include +#include +#include +#include +// using boost::math::policies::policy; +// using boost::math::complement; // will be needed by users who want complement, +// but NOT placed here to avoid putting it in global scope. + +namespace boost +{ + namespace math + { + // Function to find location of random variable z + // to give probability p (given scale) + // Applies to normal, lognormal, extreme value, Cauchy, (and symmetrical triangular), + // enforced by BOOST_STATIC_ASSERT below. + + template + inline + typename Dist::value_type find_location( // For example, normal mean. + typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p. + // For example, a nominal minimum acceptable z, so that p * 100 % are > z + typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z. + typename Dist::value_type scale, // scale parameter, for example, normal standard deviation. + const Policy& pol + ) + { +#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + // Will fail to compile here if try to use with a distribution without scale & location, + // for example pareto, and many others. These tests are disabled by the pp-logic + // above if the compiler doesn't support the SFINAE tricks used in the traits class. + BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution::value); + BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution::value); +#endif + static const char* function = "boost::math::find_location&, %1%)"; + + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, pol); + } + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "z parameter was %1%, but must be finite!", z, pol); + } + if(!(boost::math::isfinite)(scale)) + { + return policies::raise_domain_error( + function, "scale parameter was %1%, but must be finite!", scale, pol); + } + + //cout << "z " << z << ", p " << p << ", quantile(Dist(), p) " + // << quantile(Dist(), p) << ", quan * scale " << quantile(Dist(), p) * scale << endl; + return z - (quantile(Dist(), p) * scale); + } // find_location + + template + inline // with default policy. + typename Dist::value_type find_location( // For example, normal mean. + typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p. + // For example, a nominal minimum acceptable z, so that p * 100 % are > z + typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z. + typename Dist::value_type scale) // scale parameter, for example, normal standard deviation. + { // Forward to find_location with default policy. + return (find_location(z, p, scale, policies::policy<>())); + } // find_location + + // So the user can start from the complement q = (1 - p) of the probability p, + // for example, l = find_location(complement(z, q, sd)); + + template + inline typename Dist::value_type find_location( // Default policy. + complemented3_type const& c) + { + static const char* function = "boost::math::find_location&, %1%)"; + + typename Dist::value_type p = c.param1; + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, policies::policy<>()); + } + typename Dist::value_type z = c.dist; + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "z parameter was %1%, but must be finite!", z, policies::policy<>()); + } + typename Dist::value_type scale = c.param2; + if(!(boost::math::isfinite)(scale)) + { + return policies::raise_domain_error( + function, "scale parameter was %1%, but must be finite!", scale, policies::policy<>()); + } + // cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl; + return z - quantile(Dist(), p) * scale; + } // find_location complement + + + template + inline typename Dist::value_type find_location( // Explicit policy. + complemented4_type const& c) + { + static const char* function = "boost::math::find_location&, %1%)"; + + typename Dist::value_type p = c.param1; + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, c.param3); + } + typename Dist::value_type z = c.dist; + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "z parameter was %1%, but must be finite!", z, c.param3); + } + typename Dist::value_type scale = c.param2; + if(!(boost::math::isfinite)(scale)) + { + return policies::raise_domain_error( + function, "scale parameter was %1%, but must be finite!", scale, c.param3); + } + // cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl; + return z - quantile(Dist(), p) * scale; + } // find_location complement + + } // namespace boost +} // namespace math + +#endif // BOOST_STATS_FIND_LOCATION_HPP + diff --git a/include/boost/math/distributions/find_scale.hpp b/include/boost/math/distributions/find_scale.hpp new file mode 100644 index 000000000..778c02af4 --- /dev/null +++ b/include/boost/math/distributions/find_scale.hpp @@ -0,0 +1,209 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_FIND_SCALE_HPP +#define BOOST_STATS_FIND_SCALE_HPP + +#include // for all distribution signatures. +#include +#include +// using boost::math::policies::policy; +#include +#include +// using boost::math::complement; // will be needed by users who want complement, +// but NOT placed here to avoid putting it in global scope. + +namespace boost +{ + namespace math + { + // Function to find location of random variable z + // to give probability p (given scale) + // Applies to normal, lognormal, extreme value, Cauchy, (and symmetrical triangular), + // distributions that have scale. + // BOOST_STATIC_ASSERTs, see below, are used to enforce this. + + template + inline + typename Dist::value_type find_scale( // For example, normal mean. + typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p. + // For example, a nominal minimum acceptable weight z, so that p * 100 % are > z + typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z. + typename Dist::value_type location, // location parameter, for example, normal distribution mean. + const Policy& pol + ) + { +#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution::value); + BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution::value); +#endif + static const char* function = "boost::math::find_scale(%1%, %1%, %1%, Policy)"; + + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, pol); + } + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "find_scale z parameter was %1%, but must be finite!", z, pol); + } + if(!(boost::math::isfinite)(location)) + { + return policies::raise_domain_error( + function, "find_scale location parameter was %1%, but must be finite!", location, pol); + } + + //cout << "z " << z << ", p " << p << ", quantile(Dist(), p) " + //<< quantile(Dist(), p) << ", z - mean " << z - location + //<<", sd " << (z - location) / quantile(Dist(), p) << endl; + + //quantile(N01, 0.001) -3.09023 + //quantile(N01, 0.01) -2.32635 + //quantile(N01, 0.05) -1.64485 + //quantile(N01, 0.333333) -0.430728 + //quantile(N01, 0.5) 0 + //quantile(N01, 0.666667) 0.430728 + //quantile(N01, 0.9) 1.28155 + //quantile(N01, 0.95) 1.64485 + //quantile(N01, 0.99) 2.32635 + //quantile(N01, 0.999) 3.09023 + + typename Dist::value_type result = + (z - location) // difference between desired x and current location. + / quantile(Dist(), p); // standard distribution. + + if (result <= 0) + { // If policy isn't to throw, return the scale <= 0. + policies::raise_evaluation_error(function, + "Computed scale (%1%) is <= 0!" " Was the complement intended?", + result, Policy()); + } + return result; + } // template find_scale + + template + inline // with default policy. + typename Dist::value_type find_scale( // For example, normal mean. + typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p. + // For example, a nominal minimum acceptable z, so that p * 100 % are > z + typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z. + typename Dist::value_type location) // location parameter, for example, mean. + { // Forward to find_scale using the default policy. + return (find_scale(z, p, location, policies::policy<>())); + } // find_scale + + template + inline typename Dist::value_type find_scale( + complemented4_type const& c) + { + //cout << "cparam1 q " << c.param1 // q + // << ", c.dist z " << c.dist // z + // << ", c.param2 l " << c.param2 // l + // << ", quantile (Dist(), c.param1 = q) " + // << quantile(Dist(), c.param1) //q + // << endl; + +#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution::value); + BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution::value); +#endif + static const char* function = "boost::math::find_scale(complement(%1%, %1%, %1%, Policy))"; + + // Checks on arguments, as not complemented version, + // Explicit policy. + typename Dist::value_type q = c.param1; + if(!(boost::math::isfinite)(q) || (q < 0) || (q > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", q, c.param3); + } + typename Dist::value_type z = c.dist; + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "find_scale z parameter was %1%, but must be finite!", z, c.param3); + } + typename Dist::value_type location = c.param2; + if(!(boost::math::isfinite)(location)) + { + return policies::raise_domain_error( + function, "find_scale location parameter was %1%, but must be finite!", location, c.param3); + } + + typename Dist::value_type result = + (c.dist - c.param2) // difference between desired x and current location. + / quantile(complement(Dist(), c.param1)); + // ( z - location) / (quantile(complement(Dist(), q)) + if (result <= 0) + { // If policy isn't to throw, return the scale <= 0. + policies::raise_evaluation_error(function, + "Computed scale (%1%) is <= 0!" " Was the complement intended?", + result, Policy()); + } + return result; + } // template typename Dist::value_type find_scale + + // So the user can start from the complement q = (1 - p) of the probability p, + // for example, s = find_scale(complement(z, q, l)); + + template + inline typename Dist::value_type find_scale( + complemented3_type const& c) + { + //cout << "cparam1 q " << c.param1 // q + // << ", c.dist z " << c.dist // z + // << ", c.param2 l " << c.param2 // l + // << ", quantile (Dist(), c.param1 = q) " + // << quantile(Dist(), c.param1) //q + // << endl; + +#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution::value); + BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution::value); +#endif + static const char* function = "boost::math::find_scale(complement(%1%, %1%, %1%, Policy))"; + + // Checks on arguments, as not complemented version, + // default policy policies::policy<>(). + typename Dist::value_type q = c.param1; + if(!(boost::math::isfinite)(q) || (q < 0) || (q > 1)) + { + return policies::raise_domain_error( + function, "Probability parameter was %1%, but must be >= 0 and <= 1!", q, policies::policy<>()); + } + typename Dist::value_type z = c.dist; + if(!(boost::math::isfinite)(z)) + { + return policies::raise_domain_error( + function, "find_scale z parameter was %1%, but must be finite!", z, policies::policy<>()); + } + typename Dist::value_type location = c.param2; + if(!(boost::math::isfinite)(location)) + { + return policies::raise_domain_error( + function, "find_scale location parameter was %1%, but must be finite!", location, policies::policy<>()); + } + + typename Dist::value_type result = + (z - location) // difference between desired x and current location. + / quantile(complement(Dist(), q)); + // ( z - location) / (quantile(complement(Dist(), q)) + if (result <= 0) + { // If policy isn't to throw, return the scale <= 0. + policies::raise_evaluation_error(function, + "Computed scale (%1%) is <= 0!" " Was the complement intended?", + result, policies::policy<>()); // This is only the default policy - also Want a version with Policy here. + } + return result; + } // template typename Dist::value_type find_scale + + } // namespace boost +} // namespace math + +#endif // BOOST_STATS_FIND_SCALE_HPP diff --git a/include/boost/math/distributions/fisher_f.hpp b/include/boost/math/distributions/fisher_f.hpp new file mode 100644 index 000000000..8e020b7d0 --- /dev/null +++ b/include/boost/math/distributions/fisher_f.hpp @@ -0,0 +1,385 @@ +// Copyright John Maddock 2006. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_DISTRIBUTIONS_FISHER_F_HPP +#define BOOST_MATH_DISTRIBUTIONS_FISHER_F_HPP + +#include +#include // for incomplete beta. +#include // complements +#include // error checks +#include + +#include + +namespace boost{ namespace math{ + +template > +class fisher_f_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + fisher_f_distribution(const RealType& i, const RealType& j) : m_df1(i), m_df2(j) + { + static const char* function = "fisher_f_distribution<%1%>::fisher_f_distribution"; + RealType result; + detail::check_df( + function, m_df1, &result, Policy()); + detail::check_df( + function, m_df2, &result, Policy()); + } // fisher_f_distribution + + RealType degrees_of_freedom1()const + { + return m_df1; + } + RealType degrees_of_freedom2()const + { + return m_df2; + } + +private: + // + // Data members: + // + RealType m_df1; // degrees of freedom are a real number. + RealType m_df2; // degrees of freedom are a real number. +}; + +typedef fisher_f_distribution fisher_f; + +template +inline const std::pair range(const fisher_f_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline const std::pair support(const fisher_f_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +RealType pdf(const fisher_f_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + static const char* function = "boost::math::pdf(fisher_f_distribution<%1%> const&, %1%)"; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + + if((x < 0) || !(boost::math::isfinite)(x)) + { + return policies::raise_domain_error( + function, "Random variable parameter was %1%, but must be > 0 !", x, Policy()); + } + + if(x == 0) + { + // special cases: + if(df1 < 2) + return policies::raise_overflow_error( + function, 0, Policy()); + else if(df1 == 2) + return 1; + else + return 0; + } + + // + // You reach this formula by direct differentiation of the + // cdf expressed in terms of the incomplete beta. + // + // There are two versions so we don't pass a value of z + // that is very close to 1 to ibeta_derivative: for some values + // of df1 and df2, all the change takes place in this area. + // + RealType v1x = df1 * x; + RealType result; + if(v1x > df2) + { + result = (df2 * df1) / ((df2 + v1x) * (df2 + v1x)); + result *= ibeta_derivative(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy()); + } + else + { + result = df2 + df1 * x; + result = (result * df1 - x * df1 * df1) / (result * result); + result *= ibeta_derivative(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy()); + } + return result; +} // pdf + +template +inline RealType cdf(const fisher_f_distribution& dist, const RealType& x) +{ + static const char* function = "boost::math::cdf(fisher_f_distribution<%1%> const&, %1%)"; + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + + if((x < 0) || !(boost::math::isfinite)(x)) + { + return policies::raise_domain_error( + function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy()); + } + + RealType v1x = df1 * x; + // + // There are two equivalent formulas used here, the aim is + // to prevent the final argument to the incomplete beta + // from being too close to 1: for some values of df1 and df2 + // the rate of change can be arbitrarily large in this area, + // whilst the value we're passing will have lost information + // content as a result of being 0.999999something. Better + // to switch things around so we're passing 1-z instead. + // + return v1x > df2 + ? boost::math::ibetac(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy()) + : boost::math::ibeta(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy()); +} // cdf + +template +inline RealType quantile(const fisher_f_distribution& dist, const RealType& p) +{ + static const char* function = "boost::math::quantile(fisher_f_distribution<%1%> const&, %1%)"; + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy()) + && detail::check_probability( + function, p, &error_result, Policy())) + return error_result; + + RealType x, y; + + x = boost::math::ibeta_inv(df1 / 2, df2 / 2, p, &y, Policy()); + + return df2 * x / (df1 * y); +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + static const char* function = "boost::math::cdf(fisher_f_distribution<%1%> const&, %1%)"; + RealType df1 = c.dist.degrees_of_freedom1(); + RealType df2 = c.dist.degrees_of_freedom2(); + RealType x = c.param; + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + + if((x < 0) || !(boost::math::isfinite)(x)) + { + return policies::raise_domain_error( + function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy()); + } + + RealType v1x = df1 * x; + // + // There are two equivalent formulas used here, the aim is + // to prevent the final argument to the incomplete beta + // from being too close to 1: for some values of df1 and df2 + // the rate of change can be arbitrarily large in this area, + // whilst the value we're passing will have lost information + // content as a result of being 0.999999something. Better + // to switch things around so we're passing 1-z instead. + // + return v1x > df2 + ? boost::math::ibeta(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy()) + : boost::math::ibetac(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy()); +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + static const char* function = "boost::math::quantile(fisher_f_distribution<%1%> const&, %1%)"; + RealType df1 = c.dist.degrees_of_freedom1(); + RealType df2 = c.dist.degrees_of_freedom2(); + RealType p = c.param; + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy()) + && detail::check_probability( + function, p, &error_result, Policy())) + return error_result; + + RealType x, y; + + x = boost::math::ibetac_inv(df1 / 2, df2 / 2, p, &y, Policy()); + + return df2 * x / (df1 * y); +} + +template +inline RealType mean(const fisher_f_distribution& dist) +{ // Mean of F distribution = v. + static const char* function = "boost::math::mean(fisher_f_distribution<%1%> const&)"; + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + if(df2 <= 2) + { + return policies::raise_domain_error( + function, "Second degree of freedom was %1% but must be > 2 in order for the distribution to have a mean.", df2, Policy()); + } + return df2 / (df2 - 2); +} // mean + +template +inline RealType variance(const fisher_f_distribution& dist) +{ // Variance of F distribution. + static const char* function = "boost::math::variance(fisher_f_distribution<%1%> const&)"; + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + if(df2 <= 4) + { + return policies::raise_domain_error( + function, "Second degree of freedom was %1% but must be > 4 in order for the distribution to have a valid variance.", df2, Policy()); + } + return 2 * df2 * df2 * (df1 + df2 - 2) / (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4)); +} // variance + +template +inline RealType mode(const fisher_f_distribution& dist) +{ + static const char* function = "boost::math::mode(fisher_f_distribution<%1%> const&)"; + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + if(df2 <= 2) + { + return policies::raise_domain_error( + function, "Second degree of freedom was %1% but must be > 2 in order for the distribution to have a mode.", df2, Policy()); + } + return df2 * (df1 - 2) / (df1 * (df2 + 2)); +} + +//template +//inline RealType median(const fisher_f_distribution& dist) +//{ // Median of Fisher F distribution is not defined. +// return tools::domain_error(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits::quiet_NaN()); +// } // median + +// Now implemented via quantile(half) in derived accessors. + +template +inline RealType skewness(const fisher_f_distribution& dist) +{ + static const char* function = "boost::math::skewness(fisher_f_distribution<%1%> const&)"; + BOOST_MATH_STD_USING // ADL of std names + // See http://mathworld.wolfram.com/F-Distribution.html + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + if(df2 <= 6) + { + return policies::raise_domain_error( + function, "Second degree of freedom was %1% but must be > 6 in order for the distribution to have a skewness.", df2, Policy()); + } + return 2 * (df2 + 2 * df1 - 2) * sqrt((2 * df2 - 8) / (df1 * (df2 + df1 - 2))) / (df2 - 6); +} + +template +RealType kurtosis_excess(const fisher_f_distribution& dist); + +template +inline RealType kurtosis(const fisher_f_distribution& dist) +{ + return 3 + kurtosis_excess(dist); +} + +template +inline RealType kurtosis_excess(const fisher_f_distribution& dist) +{ + static const char* function = "boost::math::kurtosis_excess(fisher_f_distribution<%1%> const&)"; + // See http://mathworld.wolfram.com/F-Distribution.html + RealType df1 = dist.degrees_of_freedom1(); + RealType df2 = dist.degrees_of_freedom2(); + // Error check: + RealType error_result; + if(false == detail::check_df( + function, df1, &error_result, Policy()) + && detail::check_df( + function, df2, &error_result, Policy())) + return error_result; + if(df2 <= 8) + { + return policies::raise_domain_error( + function, "Second degree of freedom was %1% but must be > 8 in order for the distribution to have a kutosis.", df2, Policy()); + } + RealType df2_2 = df2 * df2; + RealType df1_2 = df1 * df1; + RealType n = -16 + 20 * df2 - 8 * df2_2 + df2_2 * df2 + 44 * df1 - 32 * df2 * df1 + 5 * df2_2 * df1 - 22 * df1_2 + 5 * df2 * df1_2; + n *= 12; + RealType d = df1 * (df2 - 6) * (df2 - 8) * (df1 + df2 - 2); + return n / d; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_MATH_DISTRIBUTIONS_FISHER_F_HPP diff --git a/include/boost/math/distributions/fwd.hpp b/include/boost/math/distributions/fwd.hpp new file mode 100644 index 000000000..20a18d844 --- /dev/null +++ b/include/boost/math/distributions/fwd.hpp @@ -0,0 +1,94 @@ +// Copyright Paul A. Bristow 2007. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_DISTRIBUTIONS_FWD_HPP +#define BOOST_MATH_DISTRIBUTIONS_FWD_HPP + +namespace boost{ namespace math{ + +template +class bernoulli_distribution; + +template +class beta_distribution; + +template +class binomial_distribution; + +template +class cauchy_distribution; + +template +class chi_squared_distribution; + +template +class exponential_distribution; + +template +class extreme_value_distribution; + +template +class fisher_f_distribution; + +template +class gamma_distribution; + +template +class lognormal_distribution; + +template +class negative_binomial_distribution; + +template +class normal_distribution; + +template +class pareto_distribution; + +template +class poisson_distribution; + +template +class rayleigh_distribution; + +template +class students_t_distribution; + +template +class triangular_distribution; + +template +class uniform_distribution; + +template +class weibull_distribution; + +}} // namespaces + +#define BOOST_MATH_DECLARE_DISTRIBUTIONS(Type, Policy)\ + typedef boost::math::bernoulli_distribution bernoulli;\ + typedef boost::math::beta_distribution beta;\ + typedef boost::math::binomial_distribution binomial;\ + typedef boost::math::cauchy_distribution cauchy;\ + typedef boost::math::chi_squared_distribution chi_squared;\ + typedef boost::math::exponential_distribution exponential;\ + typedef boost::math::extreme_value_distribution extreme_value;\ + typedef boost::math::fisher_f_distribution fisher_f;\ + typedef boost::math::gamma_distribution gamma;\ + typedef boost::math::lognormal_distribution lognormal;\ + typedef boost::math::negative_binomial_distribution negative_binomial;\ + typedef boost::math::normal_distribution normal;\ + typedef boost::math::pareto_distribution pareto;\ + typedef boost::math::poisson_distribution poisson;\ + typedef boost::math::rayleigh_distribution rayleigh;\ + typedef boost::math::students_t_distribution students_t;\ + typedef boost::math::triangular_distribution triangular;\ + typedef boost::math::uniform_distribution uniform;\ + typedef boost::math::weibull_distribution weibull;\ + +#endif // BOOST_MATH_DISTRIBUTIONS_FWD_HPP diff --git a/include/boost/math/distributions/gamma.hpp b/include/boost/math/distributions/gamma.hpp new file mode 100644 index 000000000..5ac4bb370 --- /dev/null +++ b/include/boost/math/distributions/gamma.hpp @@ -0,0 +1,348 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_GAMMA_HPP +#define BOOST_STATS_GAMMA_HPP + +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366b.htm +// http://mathworld.wolfram.com/GammaDistribution.html +// http://en.wikipedia.org/wiki/Gamma_distribution + +#include +#include +#include +#include + +#include + +namespace boost{ namespace math +{ +namespace detail +{ + +template +inline bool check_gamma_shape( + const char* function, + RealType shape, + RealType* result, const Policy& pol) +{ + if((shape <= 0) || !(boost::math::isfinite)(shape)) + { + *result = policies::raise_domain_error( + function, + "Shape parameter is %1%, but must be > 0 !", shape, pol); + return false; + } + return true; +} + +template +inline bool check_gamma_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) +{ + if((x < 0) || !(boost::math::isfinite)(x)) + { + *result = policies::raise_domain_error( + function, + "Random variate is %1% but must be >= 0 !", x, pol); + return false; + } + return true; +} + +template +inline bool check_gamma( + const char* function, + RealType scale, + RealType shape, + RealType* result, const Policy& pol) +{ + return check_scale(function, scale, result, pol) && check_gamma_shape(function, shape, result, pol); +} + +} // namespace detail + +template > +class gamma_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + gamma_distribution(RealType shape, RealType scale = 1) + : m_shape(shape), m_scale(scale) + { + RealType result; + detail::check_gamma("boost::math::gamma_distribution<%1%>::gamma_distribution", scale, shape, &result, Policy()); + } + + RealType shape()const + { + return m_shape; + } + + RealType scale()const + { + return m_scale; + } +private: + // + // Data members: + // + RealType m_shape; // distribution shape + RealType m_scale; // distribution scale +}; + +// NO typedef because of clash with name of gamma function. + +template +inline const std::pair range(const gamma_distribution& /* dist */) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline const std::pair support(const gamma_distribution& /* dist */) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline RealType pdf(const gamma_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::pdf(const gamma_distribution<%1%>&, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_gamma_x(function, x, &result, Policy())) + return result; + + if(x == 0) + { + return 0; + } + result = gamma_p_derivative(shape, x / scale, Policy()) / scale; + return result; +} // pdf + +template +inline RealType cdf(const gamma_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const gamma_distribution<%1%>&, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_gamma_x(function, x, &result, Policy())) + return result; + + result = boost::math::gamma_p(shape, x / scale, Policy()); + return result; +} // cdf + +template +inline RealType quantile(const gamma_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 1) + return policies::raise_overflow_error(function, 0, Policy()); + + result = gamma_p_inv(shape, p, Policy()) * scale; + + return result; +} + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)"; + + RealType shape = c.dist.shape(); + RealType scale = c.dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_gamma_x(function, c.param, &result, Policy())) + return result; + + result = gamma_q(shape, c.param / scale, Policy()); + + return result; +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)"; + + RealType shape = c.dist.shape(); + RealType scale = c.dist.scale(); + RealType q = c.param; + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_probability(function, q, &result, Policy())) + return result; + + if(q == 0) + return policies::raise_overflow_error(function, 0, Policy()); + + result = gamma_q_inv(shape, q, Policy()) * scale; + + return result; +} + +template +inline RealType mean(const gamma_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::mean(const gamma_distribution<%1%>&)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + + result = shape * scale; + return result; +} + +template +inline RealType variance(const gamma_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::variance(const gamma_distribution<%1%>&)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + + result = shape * scale * scale; + return result; +} + +template +inline RealType mode(const gamma_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::mode(const gamma_distribution<%1%>&)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + + if(shape < 1) + return policies::raise_domain_error( + function, + "The mode of the gamma distribution is only defined for values of the shape parameter >= 1, but got %1%.", + shape, Policy()); + + result = (shape - 1) * scale; + return result; +} + +//template +//inline RealType median(const gamma_distribution& dist) +//{ // Rely on default definition in derived accessors. +//} + +template +inline RealType skewness(const gamma_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::skewness(const gamma_distribution<%1%>&)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + + result = 2 / sqrt(shape); + return result; +} + +template +inline RealType kurtosis_excess(const gamma_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::kurtosis_excess(const gamma_distribution<%1%>&)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_gamma(function, scale, shape, &result, Policy())) + return result; + + result = 6 / shape; + return result; +} + +template +inline RealType kurtosis(const gamma_distribution& dist) +{ + return kurtosis_excess(dist) + 3; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_GAMMA_HPP + + diff --git a/include/boost/math/distributions/lognormal.hpp b/include/boost/math/distributions/lognormal.hpp new file mode 100644 index 000000000..a496e4a14 --- /dev/null +++ b/include/boost/math/distributions/lognormal.hpp @@ -0,0 +1,310 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_LOGNORMAL_HPP +#define BOOST_STATS_LOGNORMAL_HPP + +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3669.htm +// http://mathworld.wolfram.com/LogNormalDistribution.html +// http://en.wikipedia.org/wiki/Lognormal_distribution + +#include +#include +#include +#include + +#include + +namespace boost{ namespace math +{ +namespace detail +{ + + template + inline bool check_lognormal_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) + { + if((x < 0) || !(boost::math::isfinite)(x)) + { + *result = policies::raise_domain_error( + function, + "Random variate is %1% but must be >= 0 !", x, pol); + return false; + } + return true; + } + +} // namespace detail + + +template > +class lognormal_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + lognormal_distribution(RealType location = 0, RealType scale = 1) + : m_location(location), m_scale(scale) + { + RealType result; + detail::check_scale("boost::math::lognormal_distribution<%1%>::lognormal_distribution", scale, &result, Policy()); + } + + RealType location()const + { + return m_location; + } + + RealType scale()const + { + return m_scale; + } +private: + // + // Data members: + // + RealType m_location; // distribution location. + RealType m_scale; // distribution scale. +}; + +typedef lognormal_distribution lognormal; + +template +inline const std::pair range(const lognormal_distribution& /*dist*/) +{ // Range of permissible values for random variable x is >0 to +infinity. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline const std::pair support(const lognormal_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +RealType pdf(const lognormal_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType mu = dist.location(); + RealType sigma = dist.scale(); + + static const char* function = "boost::math::pdf(const lognormal_distribution<%1%>&, %1%)"; + + RealType result; + if(0 == detail::check_scale(function, sigma, &result, Policy())) + return result; + if(0 == detail::check_lognormal_x(function, x, &result, Policy())) + return result; + + if(x == 0) + return 0; + + RealType exponent = log(x) - mu; + exponent *= -exponent; + exponent /= 2 * sigma * sigma; + + result = exp(exponent); + result /= sigma * sqrt(2 * constants::pi()) * x; + + return result; +} + +template +inline RealType cdf(const lognormal_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)"; + + RealType result; + if(0 == detail::check_lognormal_x(function, x, &result, Policy())) + return result; + + if(x == 0) + return 0; + + normal_distribution norm(dist.location(), dist.scale()); + return cdf(norm, log(x)); +} + +template +inline RealType quantile(const lognormal_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)"; + + RealType result; + if(0 == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 0) + return 0; + if(p == 1) + return policies::raise_overflow_error(function, 0, Policy()); + + normal_distribution norm(dist.location(), dist.scale()); + return exp(quantile(norm, p)); +} + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)"; + + RealType result; + if(0 == detail::check_lognormal_x(function, c.param, &result, Policy())) + return result; + + if(c.param == 0) + return 1; + + normal_distribution norm(c.dist.location(), c.dist.scale()); + return cdf(complement(norm, log(c.param))); +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)"; + + RealType result; + if(0 == detail::check_probability(function, c.param, &result, Policy())) + return result; + + if(c.param == 1) + return 0; + if(c.param == 0) + return policies::raise_overflow_error(function, 0, Policy()); + + normal_distribution norm(c.dist.location(), c.dist.scale()); + return exp(quantile(complement(norm, c.param))); +} + +template +inline RealType mean(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType mu = dist.location(); + RealType sigma = dist.scale(); + + RealType result; + if(0 == detail::check_scale("boost::math::mean(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return exp(mu + sigma * sigma / 2); +} + +template +inline RealType variance(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType mu = dist.location(); + RealType sigma = dist.scale(); + + RealType result; + if(0 == detail::check_scale("boost::math::variance(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return boost::math::expm1(sigma * sigma, Policy()) * exp(2 * mu + sigma * sigma); +} + +template +inline RealType mode(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType mu = dist.location(); + RealType sigma = dist.scale(); + + RealType result; + if(0 == detail::check_scale("boost::math::mode(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return exp(mu - sigma * sigma); +} + +template +inline RealType median(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + RealType mu = dist.location(); + return exp(mu); // e^mu +} + +template +inline RealType skewness(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + //RealType mu = dist.location(); + RealType sigma = dist.scale(); + + RealType ss = sigma * sigma; + RealType ess = exp(ss); + + RealType result; + if(0 == detail::check_scale("boost::math::skewness(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return (ess + 2) * sqrt(boost::math::expm1(ss, Policy())); +} + +template +inline RealType kurtosis(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + //RealType mu = dist.location(); + RealType sigma = dist.scale(); + RealType ss = sigma * sigma; + + RealType result; + if(0 == detail::check_scale("boost::math::kurtosis(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 3; +} + +template +inline RealType kurtosis_excess(const lognormal_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + // RealType mu = dist.location(); + RealType sigma = dist.scale(); + RealType ss = sigma * sigma; + + RealType result; + if(0 == detail::check_scale("boost::math::kurtosis_excess(const lognormal_distribution<%1%>&)", sigma, &result, Policy())) + return result; + + return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 6; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_STUDENTS_T_HPP + + diff --git a/include/boost/math/distributions/negative_binomial.hpp b/include/boost/math/distributions/negative_binomial.hpp new file mode 100644 index 000000000..ccc8127b1 --- /dev/null +++ b/include/boost/math/distributions/negative_binomial.hpp @@ -0,0 +1,588 @@ +// boost\math\special_functions\negative_binomial.hpp + +// Copyright Paul A. Bristow 2007. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// http://en.wikipedia.org/wiki/negative_binomial_distribution +// http://mathworld.wolfram.com/NegativeBinomialDistribution.html +// http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html + +// The negative binomial distribution NegativeBinomialDistribution[n, p] +// is the distribution of the number (k) of failures that occur in a sequence of trials before +// r successes have occurred, where the probability of success in each trial is p. + +// In a sequence of Bernoulli trials or events +// (independent, yes or no, succeed or fail) with success_fraction probability p, +// negative_binomial is the probability that k or fewer failures +// preceed the r th trial's success. +// random variable k is the number of failures (NOT the probability). + +// Negative_binomial distribution is a discrete probability distribution. +// But note that the negative binomial distribution +// (like others including the binomial, Poisson & Bernoulli) +// is strictly defined as a discrete function: only integral values of k are envisaged. +// However because of the method of calculation using a continuous gamma function, +// it is convenient to treat it as if a continous function, +// and permit non-integral values of k. + +// However, by default the policy is to use discrete_quantile_policy. + +// To enforce the strict mathematical model, users should use conversion +// on k outside this function to ensure that k is integral. + +// MATHCAD cumulative negative binomial pnbinom(k, n, p) + +// Implementation note: much greater speed, and perhaps greater accuracy, +// might be achieved for extreme values by using a normal approximation. +// This is NOT been tested or implemented. + +#ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP +#define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP + +#include +#include // for ibeta(a, b, x) == Ix(a, b). +#include // complement. +#include // error checks domain_error & logic_error. +#include // isnan. +#include // for root finding. +#include + +#include +#include +#include +#include + +#include // using std::numeric_limits; +#include + +#if defined (BOOST_MSVC) +# pragma warning(push) +// This believed not now necessary, so commented out. +//# pragma warning(disable: 4702) // unreachable code. +// in domain_error_imp in error_handling. +#endif + +namespace boost +{ + namespace math + { + namespace negative_binomial_detail + { + // Common error checking routines for negative binomial distribution functions: + template + inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol) + { + if( !(boost::math::isfinite)(r) || (r <= 0) ) + { + *result = policies::raise_domain_error( + function, + "Number of successes argument is %1%, but must be > 0 !", r, pol); + return false; + } + return true; + } + template + inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol) + { + if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) ) + { + *result = policies::raise_domain_error( + function, + "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol); + return false; + } + return true; + } + template + inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol) + { + return check_success_fraction(function, p, result, pol) + && check_successes(function, r, result, pol); + } + template + inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol) + { + if(check_dist(function, r, p, result, pol) == false) + { + return false; + } + if( !(boost::math::isfinite)(k) || (k < 0) ) + { // Check k failures. + *result = policies::raise_domain_error( + function, + "Number of failures argument is %1%, but must be >= 0 !", k, pol); + return false; + } + return true; + } // Check_dist_and_k + + template + inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol) + { + if(check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol) == false) + { + return false; + } + return true; + } // check_dist_and_prob + } // namespace negative_binomial_detail + + template > + class negative_binomial_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p) + { // Constructor. + RealType result; + negative_binomial_detail::check_dist( + "negative_binomial_distribution<%1%>::negative_binomial_distribution", + m_r, // Check successes r > 0. + m_p, // Check success_fraction 0 <= p <= 1. + &result, Policy()); + } // negative_binomial_distribution constructor. + + // Private data getter class member functions. + RealType success_fraction() const + { // Probability of success as fraction in range 0 to 1. + return m_p; + } + RealType successes() const + { // Total number of successes r. + return m_r; + } + + static RealType find_lower_bound_on_p( + RealType trials, + RealType successes, + RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test. + { + static const char* function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p"; + RealType result; // of error checks. + RealType failures = trials - successes; + if(false == detail::check_probability(function, alpha, &result, Policy()) + && negative_binomial_detail::check_dist_and_k( + function, successes, RealType(0), failures, &result, Policy())) + { + return result; + } + // Use complement ibeta_inv function for lower bound. + // This is adapted from the corresponding binomial formula + // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm + // This is a Clopper-Pearson interval, and may be overly conservative, + // see also "A Simple Improved Inferential Method for Some + // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY + // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf + // + return ibeta_inv(successes, failures + 1, alpha, static_cast(0), Policy()); + } // find_lower_bound_on_p + + static RealType find_upper_bound_on_p( + RealType trials, + RealType successes, + RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test. + { + static const char* function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p"; + RealType result; // of error checks. + RealType failures = trials - successes; + if(false == negative_binomial_detail::check_dist_and_k( + function, successes, RealType(0), failures, &result, Policy()) + && detail::check_probability(function, alpha, &result, Policy())) + { + return result; + } + if(failures == 0) + return 1; + // Use complement ibetac_inv function for upper bound. + // Note adjusted failures value: *not* failures+1 as usual. + // This is adapted from the corresponding binomial formula + // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm + // This is a Clopper-Pearson interval, and may be overly conservative, + // see also "A Simple Improved Inferential Method for Some + // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY + // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf + // + return ibetac_inv(successes, failures, alpha, static_cast(0), Policy()); + } // find_upper_bound_on_p + + // Estimate number of trials : + // "How many trials do I need to be P% sure of seeing k or fewer failures?" + + static RealType find_minimum_number_of_trials( + RealType k, // number of failures (k >= 0). + RealType p, // success fraction 0 <= p <= 1. + RealType alpha) // risk level threshold 0 <= alpha <= 1. + { + static const char* function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials"; + // Error checks: + RealType result; + if(false == negative_binomial_detail::check_dist_and_k( + function, RealType(1), p, k, &result, Policy()) + && detail::check_probability(function, alpha, &result, Policy())) + { return result; } + + result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k + return result + k; + } // RealType find_number_of_failures + + static RealType find_maximum_number_of_trials( + RealType k, // number of failures (k >= 0). + RealType p, // success fraction 0 <= p <= 1. + RealType alpha) // risk level threshold 0 <= alpha <= 1. + { + static const char* function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials"; + // Error checks: + RealType result; + if(false == negative_binomial_detail::check_dist_and_k( + function, RealType(1), p, k, &result, Policy()) + && detail::check_probability(function, alpha, &result, Policy())) + { return result; } + + result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k + return result + k; + } // RealType find_number_of_trials complemented + + private: + RealType m_r; // successes. + RealType m_p; // success_fraction + }; // template class negative_binomial_distribution + + typedef negative_binomial_distribution negative_binomial; // Reserved name of type double. + + template + inline const std::pair range(const negative_binomial_distribution& /* dist */) + { // Range of permissible values for random variable k. + using boost::math::tools::max_value; + return std::pair(0, max_value()); // max_integer? + } + + template + inline const std::pair support(const negative_binomial_distribution& /* dist */) + { // Range of supported values for random variable k. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); // max_integer? + } + + template + inline RealType mean(const negative_binomial_distribution& dist) + { // Mean of Negative Binomial distribution = r(1-p)/p. + return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction(); + } // mean + + //template + //inline RealType median(const negative_binomial_distribution& dist) + //{ // Median of negative_binomial_distribution is not defined. + // return policies::raise_domain_error(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits::quiet_NaN()); + //} // median + // Now implemented via quantile(half) in derived accessors. + + template + inline RealType mode(const negative_binomial_distribution& dist) + { // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p] + BOOST_MATH_STD_USING // ADL of std functions. + return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction()); + } // mode + + template + inline RealType skewness(const negative_binomial_distribution& dist) + { // skewness of Negative Binomial distribution = 2-p / (sqrt(r(1-p)) + BOOST_MATH_STD_USING // ADL of std functions. + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + + return (2 - p) / + sqrt(r * (1 - p)); + } // skewness + + template + inline RealType kurtosis(const negative_binomial_distribution& dist) + { // kurtosis of Negative Binomial distribution + // http://en.wikipedia.org/wiki/Negative_binomial is kurtosis_excess so add 3 + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + return 3 + (6 / r) + ((p * p) / (r * (1 - p))); + } // kurtosis + + template + inline RealType kurtosis_excess(const negative_binomial_distribution& dist) + { // kurtosis excess of Negative Binomial distribution + // http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + return (6 - p * (6-p)) / (r * (1-p)); + } // kurtosis_excess + + template + inline RealType variance(const negative_binomial_distribution& dist) + { // Variance of Binomial distribution = r (1-p) / p^2. + return dist.successes() * (1 - dist.success_fraction()) + / (dist.success_fraction() * dist.success_fraction()); + } // variance + + // RealType standard_deviation(const negative_binomial_distribution& dist) + // standard_deviation provided by derived accessors. + // RealType hazard(const negative_binomial_distribution& dist) + // hazard of Negative Binomial distribution provided by derived accessors. + // RealType chf(const negative_binomial_distribution& dist) + // chf of Negative Binomial distribution provided by derived accessors. + + template + inline RealType pdf(const negative_binomial_distribution& dist, const RealType& k) + { // Probability Density/Mass Function. + BOOST_FPU_EXCEPTION_GUARD + + static const char* function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)"; + + RealType r = dist.successes(); + RealType p = dist.success_fraction(); + RealType result; + if(false == negative_binomial_detail::check_dist_and_k( + function, + r, + dist.success_fraction(), + k, + &result, Policy())) + { + return result; + } + + result = (p/(r + k)) * ibeta_derivative(r, static_cast(k+1), p, Policy()); + // Equivalent to: + // return exp(lgamma(r + k) - lgamma(r) - lgamma(k+1)) * pow(p, r) * pow((1-p), k); + return result; + } // negative_binomial_pdf + + template + inline RealType cdf(const negative_binomial_distribution& dist, const RealType& k) + { // Cumulative Distribution Function of Negative Binomial. + static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)"; + using boost::math::ibeta; // Regularized incomplete beta function. + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + // Error check: + RealType result; + if(false == negative_binomial_detail::check_dist_and_k( + function, + r, + dist.success_fraction(), + k, + &result, Policy())) + { + return result; + } + + RealType probability = ibeta(r, static_cast(k+1), p, Policy()); + // Ip(r, k+1) = ibeta(r, k+1, p) + return probability; + } // cdf Cumulative Distribution Function Negative Binomial. + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function Negative Binomial. + + static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)"; + using boost::math::ibetac; // Regularized incomplete beta function complement. + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + RealType const& k = c.param; + negative_binomial_distribution const& dist = c.dist; + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + // Error check: + RealType result; + if(false == negative_binomial_detail::check_dist_and_k( + function, + r, + p, + k, + &result, Policy())) + { + return result; + } + // Calculate cdf negative binomial using the incomplete beta function. + // Use of ibeta here prevents cancellation errors in calculating + // 1-p if p is very small, perhaps smaller than machine epsilon. + // Ip(k+1, r) = ibetac(r, k+1, p) + // constrain_probability here? + RealType probability = ibetac(r, static_cast(k+1), p, Policy()); + // Numerical errors might cause probability to be slightly outside the range < 0 or > 1. + // This might cause trouble downstream, so warn, possibly throw exception, but constrain to the limits. + return probability; + } // cdf Cumulative Distribution Function Negative Binomial. + + template + inline RealType quantile(const negative_binomial_distribution& dist, const RealType& P) + { // Quantile, percentile/100 or Percent Point Negative Binomial function. + // Return the number of expected failures k for a given probability p. + + // Inverse cumulative Distribution Function or Quantile (percentile / 100) of negative_binomial Probability. + // MAthCAD pnbinom return smallest k such that negative_binomial(k, n, p) >= probability. + // k argument may be integral, signed, or unsigned, or floating point. + // BUT Cephes/CodeCogs says: finds argument p (0 to 1) such that cdf(k, n, p) = y + static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)"; + BOOST_MATH_STD_USING // ADL of std functions. + + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + // Check dist and P. + RealType result; + if(false == negative_binomial_detail::check_dist_and_prob + (function, r, p, P, &result, Policy())) + { + return result; + } + + // Special cases. + if (P == 1) + { // Would need +infinity failures for total confidence. + result = policies::raise_overflow_error( + function, + "Probability argument is 1, which implies infinite failures !", Policy()); + return result; + // usually means return +std::numeric_limits::infinity(); + // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR + } + if (P == 0) + { // No failures are expected if P = 0. + return 0; // Total trials will be just dist.successes. + } + if (P <= pow(dist.success_fraction(), dist.successes())) + { // p <= pdf(dist, 0) == cdf(dist, 0) + return 0; + } + /* + // Calculate quantile of negative_binomial using the inverse incomplete beta function. + using boost::math::ibeta_invb; + return ibeta_invb(r, p, P, Policy()) - 1; // + */ + RealType guess = 0; + RealType factor = 5; + if(r * r * r * P * p > 0.005) + guess = detail::inverse_negative_binomial_cornish_fisher(r, p, 1-p, P, 1-P, Policy()); + + if(guess < 10) + { + // + // Cornish-Fisher Negative binomial approximation not accurate in this area: + // + guess = (std::min)(r * 2, RealType(10)); + } + else + factor = (1-P < sqrt(tools::epsilon())) ? 2 : (guess < 20 ? 1.2f : 1.1f); + BOOST_MATH_INSTRUMENT_CODE("guess = " << guess); + // + // Max iterations permitted: + // + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + typedef typename Policy::discrete_quantile_type discrete_type; + return detail::inverse_discrete_quantile( + dist, + P, + 1-P, + guess, + factor, + RealType(1), + discrete_type(), + max_iter); + } // RealType quantile(const negative_binomial_distribution dist, p) + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { // Quantile or Percent Point Binomial function. + // Return the number of expected failures k for a given + // complement of the probability Q = 1 - P. + static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)"; + BOOST_MATH_STD_USING + + // Error checks: + RealType Q = c.param; + const negative_binomial_distribution& dist = c.dist; + RealType p = dist.success_fraction(); + RealType r = dist.successes(); + RealType result; + if(false == negative_binomial_detail::check_dist_and_prob( + function, + r, + p, + Q, + &result, Policy())) + { + return result; + } + + // Special cases: + // + if(Q == 1) + { // There may actually be no answer to this question, + // since the probability of zero failures may be non-zero, + return 0; // but zero is the best we can do: + } + if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy())) + { // q <= cdf(complement(dist, 0)) == pdf(dist, 0) + return 0; // + } + if(Q == 0) + { // Probability 1 - Q == 1 so infinite failures to achieve certainty. + // Would need +infinity failures for total confidence. + result = policies::raise_overflow_error( + function, + "Probability argument complement is 0, which implies infinite failures !", Policy()); + return result; + // usually means return +std::numeric_limits::infinity(); + // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR + } + //return ibetac_invb(r, p, Q, Policy()) -1; + RealType guess = 0; + RealType factor = 5; + if(r * r * r * (1-Q) * p > 0.005) + guess = detail::inverse_negative_binomial_cornish_fisher(r, p, 1-p, 1-Q, Q, Policy()); + + if(guess < 10) + { + // + // Cornish-Fisher Negative binomial approximation not accurate in this area: + // + guess = (std::min)(r * 2, RealType(10)); + } + else + factor = (Q < sqrt(tools::epsilon())) ? 2 : (guess < 20 ? 1.2f : 1.1f); + BOOST_MATH_INSTRUMENT_CODE("guess = " << guess); + // + // Max iterations permitted: + // + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + typedef typename Policy::discrete_quantile_type discrete_type; + return detail::inverse_discrete_quantile( + dist, + 1-Q, + Q, + guess, + factor, + RealType(1), + discrete_type(), + max_iter); + } // quantile complement + + } // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#if defined (BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif // BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP diff --git a/include/boost/math/distributions/normal.hpp b/include/boost/math/distributions/normal.hpp new file mode 100644 index 000000000..f3776bc5f --- /dev/null +++ b/include/boost/math/distributions/normal.hpp @@ -0,0 +1,308 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_NORMAL_HPP +#define BOOST_STATS_NORMAL_HPP + +// http://en.wikipedia.org/wiki/Normal_distribution +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm +// Also: +// Weisstein, Eric W. "Normal Distribution." +// From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/NormalDistribution.html + +#include +#include // for erf/erfc. +#include +#include + +#include + +namespace boost{ namespace math{ + +template > +class normal_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + normal_distribution(RealType mean = 0, RealType sd = 1) + : m_mean(mean), m_sd(sd) + { // Default is a 'standard' normal distribution N01. + static const char* function = "boost::math::normal_distribution<%1%>::normal_distribution"; + + RealType result; + detail::check_scale(function, sd, &result, Policy()); + detail::check_location(function, mean, &result, Policy()); + } + + RealType mean()const + { // alias for location. + return m_mean; + } + + RealType standard_deviation()const + { // alias for scale. + return m_sd; + } + + // Synonyms, provided to allow generic use of find_location and find_scale. + RealType location()const + { // location. + return m_mean; + } + RealType scale()const + { // scale. + return m_sd; + } + +private: + // + // Data members: + // + RealType m_mean; // distribution mean or location. + RealType m_sd; // distribution standard deviation or scale. +}; // class normal_distribution + +typedef normal_distribution normal; + +template +inline const std::pair range(const normal_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); // - to + max value. +} + +template +inline const std::pair support(const normal_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); // - to + max value. +} + +template +inline RealType pdf(const normal_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType sd = dist.standard_deviation(); + RealType mean = dist.mean(); + + static const char* function = "boost::math::pdf(const normal_distribution<%1%>&, %1%)"; + if((boost::math::isinf)(x)) + { + return 0; // pdf + and - infinity is zero. + } + // Theis produces MSVC 4127 warnings, so the above used instead. + //if(std::numeric_limits::has_infinity && abs(x) == std::numeric_limits::infinity()) + //{ // pdf + and - infinity is zero. + // return 0; + //} + + RealType result; + if(false == detail::check_scale(function, sd, &result, Policy())) + { + return result; + } + if(false == detail::check_location(function, mean, &result, Policy())) + { + return result; + } + if(false == detail::check_x(function, x, &result, Policy())) + { + return result; + } + + RealType exponent = x - mean; + exponent *= -exponent; + exponent /= 2 * sd * sd; + + result = exp(exponent); + result /= sd * sqrt(2 * constants::pi()); + + return result; +} // pdf + +template +inline RealType cdf(const normal_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType sd = dist.standard_deviation(); + RealType mean = dist.mean(); + static const char* function = "boost::math::cdf(const normal_distribution<%1%>&, %1%)"; + RealType result; + if(false == detail::check_scale(function, sd, &result, Policy())) + { + return result; + } + if(false == detail::check_location(function, mean, &result, Policy())) + { + return result; + } + if((boost::math::isinf)(x)) + { + if(x < 0) return 0; // -infinity + return 1; // + infinity + } + // These produce MSVC 4127 warnings, so the above used instead. + //if(std::numeric_limits::has_infinity && x == std::numeric_limits::infinity()) + //{ // cdf +infinity is unity. + // return 1; + //} + //if(std::numeric_limits::has_infinity && x == -std::numeric_limits::infinity()) + //{ // cdf -infinity is zero. + // return 0; + //} + if(false == detail::check_x(function, x, &result, Policy())) + { + return result; + } + RealType diff = (x - mean) / (sd * constants::root_two()); + result = boost::math::erfc(-diff, Policy()) / 2; + return result; +} // cdf + +template +inline RealType quantile(const normal_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType sd = dist.standard_deviation(); + RealType mean = dist.mean(); + static const char* function = "boost::math::quantile(const normal_distribution<%1%>&, %1%)"; + + RealType result; + if(false == detail::check_scale(function, sd, &result, Policy())) + return result; + if(false == detail::check_location(function, mean, &result, Policy())) + return result; + if(false == detail::check_probability(function, p, &result, Policy())) + return result; + + result= boost::math::erfc_inv(2 * p, Policy()); + result = -result; + result *= sd * constants::root_two(); + result += mean; + return result; +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType sd = c.dist.standard_deviation(); + RealType mean = c.dist.mean(); + RealType x = c.param; + static const char* function = "boost::math::cdf(const complement(normal_distribution<%1%>&), %1%)"; + + if((boost::math::isinf)(x)) + { + if(x < 0) return 1; // cdf complement -infinity is unity. + return 0; // cdf complement +infinity is zero + } + // These produce MSVC 4127 warnings, so the above used instead. + //if(std::numeric_limits::has_infinity && x == std::numeric_limits::infinity()) + //{ // cdf complement +infinity is zero. + // return 0; + //} + //if(std::numeric_limits::has_infinity && x == -std::numeric_limits::infinity()) + //{ // cdf complement -infinity is unity. + // return 1; + //} + RealType result; + if(false == detail::check_scale(function, sd, &result, Policy())) + return result; + if(false == detail::check_location(function, mean, &result, Policy())) + return result; + if(false == detail::check_x(function, x, &result, Policy())) + return result; + + RealType diff = (x - mean) / (sd * constants::root_two()); + result = boost::math::erfc(diff, Policy()) / 2; + return result; +} // cdf complement + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType sd = c.dist.standard_deviation(); + RealType mean = c.dist.mean(); + static const char* function = "boost::math::quantile(const complement(normal_distribution<%1%>&), %1%)"; + RealType result; + if(false == detail::check_scale(function, sd, &result, Policy())) + return result; + if(false == detail::check_location(function, mean, &result, Policy())) + return result; + RealType q = c.param; + if(false == detail::check_probability(function, q, &result, Policy())) + return result; + result = boost::math::erfc_inv(2 * q, Policy()); + result *= sd * constants::root_two(); + result += mean; + return result; +} // quantile + +template +inline RealType mean(const normal_distribution& dist) +{ + return dist.mean(); +} + +template +inline RealType standard_deviation(const normal_distribution& dist) +{ + return dist.standard_deviation(); +} + +template +inline RealType mode(const normal_distribution& dist) +{ + return dist.mean(); +} + +template +inline RealType median(const normal_distribution& dist) +{ + return dist.mean(); +} + +template +inline RealType skewness(const normal_distribution& /*dist*/) +{ + return 0; +} + +template +inline RealType kurtosis(const normal_distribution& /*dist*/) +{ + return 3; +} + +template +inline RealType kurtosis_excess(const normal_distribution& /*dist*/) +{ + return 0; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_NORMAL_HPP + + diff --git a/include/boost/math/distributions/pareto.hpp b/include/boost/math/distributions/pareto.hpp new file mode 100644 index 000000000..d568a5af9 --- /dev/null +++ b/include/boost/math/distributions/pareto.hpp @@ -0,0 +1,443 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_PARETO_HPP +#define BOOST_STATS_PARETO_HPP + +// http://en.wikipedia.org/wiki/Pareto_distribution +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm +// Also: +// Weisstein, Eric W. "Pareto Distribution." +// From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/ParetoDistribution.html + +#include +#include +#include +#include + +#include // for BOOST_CURRENT_VALUE? + +namespace boost +{ + namespace math + { + namespace detail + { // Parameter checking. + template + inline bool check_pareto_location( + const char* function, + RealType location, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(location)) + { // any > 0 finite value is OK. + if (location > 0) + { + return true; + } + else + { + *result = policies::raise_domain_error( + function, + "Location parameter is %1%, but must be > 0!", location, pol); + return false; + } + } + else + { // Not finite. + *result = policies::raise_domain_error( + function, + "Location parameter is %1%, but must be finite!", location, pol); + return false; + } + } // bool check_pareto_location + + template + inline bool check_pareto_shape( + const char* function, + RealType shape, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(shape)) + { // Any finite value > 0 is OK. + if (shape > 0) + { + return true; + } + else + { + *result = policies::raise_domain_error( + function, + "Shape parameter is %1%, but must be > 0!", shape, pol); + return false; + } + } + else + { // Not finite. + *result = policies::raise_domain_error( + function, + "Shape parameter is %1%, but must be finite!", shape, pol); + return false; + } + } // bool check_pareto_shape( + + template + inline bool check_pareto_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(x)) + { // + if (x > 0) + { + return true; + } + else + { + *result = policies::raise_domain_error( + function, + "x parameter is %1%, but must be > 0 !", x, pol); + return false; + } + } + else + { // Not finite.. + *result = policies::raise_domain_error( + function, + "x parameter is %1%, but must be finite!", x, pol); + return false; + } + } // bool check_pareto_x + + template + inline bool check_pareto( // distribution parameters. + const char* function, + RealType location, + RealType shape, + RealType* result, const Policy& pol) + { + return check_pareto_location(function, location, result, pol) + && check_pareto_shape(function, shape, result, pol); + } // bool check_pareto( + + } // namespace detail + + template > + class pareto_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + pareto_distribution(RealType location = 1, RealType shape = 1) + : m_location(location), m_shape(shape) + { // Constructor. + RealType result; + detail::check_pareto("boost::math::pareto_distribution<%1%>::pareto_distribution", location, shape, &result, Policy()); + } + + RealType location()const + { // AKA Xm and b + return m_location; + } + + RealType shape()const + { // AKA k and a + return m_shape; + } + private: + // Data members: + RealType m_location; // distribution location (xm) + RealType m_shape; // distribution shape (k) + }; + + typedef pareto_distribution pareto; // Convenience to allow pareto(2., 3.); + + template + inline const std::pair range(const pareto_distribution& /*dist*/) + { // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, max_value()); // location zero to + infinity. + } // range + + template + inline const std::pair support(const pareto_distribution& dist) + { // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(dist.location(), max_value() ); // location to + infinity. + } // support + + template + inline RealType pdf(const pareto_distribution& dist, const RealType& x) + { + BOOST_MATH_STD_USING // for ADL of std function pow. + static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)"; + RealType location = dist.location(); + RealType shape = dist.shape(); + RealType result; + if(false == (detail::check_pareto_x(function, x, &result, Policy()) + && detail::check_pareto(function, location, shape, &result, Policy()))) + return result; + if (x < location) + { // regardless of shape, pdf is zero. + return 0; + } + + result = shape * pow(location, shape) / pow(x, shape+1); + return result; + } // pdf + + template + inline RealType cdf(const pareto_distribution& dist, const RealType& x) + { + BOOST_MATH_STD_USING // for ADL of std function pow. + static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)"; + RealType location = dist.location(); + RealType shape = dist.shape(); + RealType result; + + if(false == (detail::check_pareto_x(function, x, &result, Policy()) + && detail::check_pareto(function, location, shape, &result, Policy()))) + return result; + + if (x <= location) + { // regardless of shape, cdf is zero. + return 0; + } + + // result = RealType(1) - pow((location / x), shape); + result = -boost::math::powm1(location/x, shape, Policy()); // should be more accurate. + return result; + } // cdf + + template + inline RealType quantile(const pareto_distribution& dist, const RealType& p) + { + BOOST_MATH_STD_USING // for ADL of std function pow. + static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)"; + RealType result; + RealType location = dist.location(); + RealType shape = dist.shape(); + if(false == (detail::check_probability(function, p, &result, Policy()) + && detail::check_pareto(function, location, shape, &result, Policy()))) + { + return result; + } + if (p == 0) + { + return location; // x must be location (or less). + } + if (p == 1) + { + return tools::max_value(); // x = + infinity. + } + result = location / + (pow((1 - p), 1 / shape)); + // K. Krishnamoorthy, ISBN 1-58488-635-8 eq 23.1.3 + return result; + } // quantile + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { + BOOST_MATH_STD_USING // for ADL of std function pow. + static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)"; + RealType result; + RealType x = c.param; + RealType location = c.dist.location(); + RealType shape = c.dist.shape(); + if(false == (detail::check_pareto_x(function, x, &result, Policy()) + && detail::check_pareto(function, location, shape, &result, Policy()))) + return result; + + if (x <= location) + { // regardless of shape, cdf is zero, and complement is unity. + return 1; + } + result = pow((location/x), shape); + + return result; + } // cdf complement + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { + BOOST_MATH_STD_USING // for ADL of std function pow. + static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)"; + RealType result; + RealType q = c.param; + RealType location = c.dist.location(); + RealType shape = c.dist.shape(); + if(false == (detail::check_probability(function, q, &result, Policy()) + && detail::check_pareto(function, location, shape, &result, Policy()))) + { + return result; + } + if (q == 1) + { + return location; // x must be location (or less). + } + if (q == 0) + { + return tools::max_value(); // x = + infinity. + } + result = location / (pow(q, 1 / shape)); + // K. Krishnamoorthy, ISBN 1-58488-635-8 eq 23.1.3 + return result; + } // quantile complement + + template + inline RealType mean(const pareto_distribution& dist) + { + RealType result; + static const char* function = "boost::math::mean(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, dist.location(), dist.shape(), &result, Policy())) + { + return result; + } + if (dist.shape() > RealType(1)) + { + return dist.shape() * dist.location() / (dist.shape() - 1); + } + else + { + using boost::math::tools::max_value; + return max_value(); // +infinity. + } + } // mean + + template + inline RealType mode(const pareto_distribution& dist) + { + return dist.location(); + } // mode + + template + inline RealType median(const pareto_distribution& dist) + { + RealType result; + static const char* function = "boost::math::median(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, dist.location(), dist.shape(), &result, Policy())) + { + return result; + } + BOOST_MATH_STD_USING + return dist.location() * pow(RealType(2), (1/dist.shape())); + } // median + + template + inline RealType variance(const pareto_distribution& dist) + { + RealType result; + RealType location = dist.location(); + RealType shape = dist.shape(); + static const char* function = "boost::math::variance(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, location, shape, &result, Policy())) + { + return result; + } + if (shape > 2) + { + result = (location * location * shape) / + ((shape - 1) * (shape - 1) * (shape - 2)); + } + else + { + result = policies::raise_domain_error( + function, + "variance is undefined for shape <= 2, but got %1%.", dist.shape(), Policy()); + } + return result; + } // variance + + template + inline RealType skewness(const pareto_distribution& dist) + { + BOOST_MATH_STD_USING + RealType result; + RealType shape = dist.shape(); + static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy())) + { + return result; + } + if (shape > 3) + { + result = sqrt((shape - 2) / shape) * + 2 * (shape + 1) / + (shape - 3); + } + else + { + result = policies::raise_domain_error( + function, + "skewness is undefined for shape <= 3, but got %1%.", dist.shape(), Policy()); + } + return result; + } // skewness + + template + inline RealType kurtosis(const pareto_distribution& dist) + { + RealType result; + RealType shape = dist.shape(); + static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy())) + { + return result; + } + if (shape > 4) + { + result = 3 * ((shape - 2) * (3 * shape * shape + shape + 2)) / + (shape * (shape - 3) * (shape - 4)); + } + else + { + result = policies::raise_domain_error( + function, + "kurtosis_excess is undefined for shape <= 4, but got %1%.", shape, Policy()); + } + return result; + } // kurtosis + + template + inline RealType kurtosis_excess(const pareto_distribution& dist) + { + RealType result; + RealType shape = dist.shape(); + static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)"; + if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy())) + { + return result; + } + if (shape > 4) + { + result = 6 * ((shape * shape * shape) + (shape * shape) - 6 * shape - 2) / + (shape * (shape - 3) * (shape - 4)); + } + else + { + result = policies::raise_domain_error( + function, + "kurtosis_excess is undefined for shape <= 4, but got %1%.", dist.shape(), Policy()); + } + return result; + } // kurtosis_excess + + } // namespace math + } // namespace boost + + // This include must be at the end, *after* the accessors + // for this distribution have been defined, in order to + // keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_PARETO_HPP + + diff --git a/include/boost/math/distributions/poisson.hpp b/include/boost/math/distributions/poisson.hpp new file mode 100644 index 000000000..9bb6e8b1c --- /dev/null +++ b/include/boost/math/distributions/poisson.hpp @@ -0,0 +1,602 @@ +// boost\math\distributions\poisson.hpp + +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Poisson distribution is a discrete probability distribution. +// It expresses the probability of a number (k) of +// events, occurrences, failures or arrivals occurring in a fixed time, +// assuming these events occur with a known average or mean rate (lambda) +// and are independent of the time since the last event. +// The distribution was discovered by Siméon-Denis Poisson (1781–1840). + +// Parameter lambda is the mean number of events in the given time interval. +// The random variate k is the number of events, occurrences or arrivals. +// k argument may be integral, signed, or unsigned, or floating point. +// If necessary, it has already been promoted from an integral type. + +// Note that the Poisson distribution +// (like others including the binomial, negative binomial & Bernoulli) +// is strictly defined as a discrete function: +// only integral values of k are envisaged. +// However because the method of calculation uses a continuous gamma function, +// it is convenient to treat it as if a continous function, +// and permit non-integral values of k. +// To enforce the strict mathematical model, users should use floor or ceil functions +// on k outside this function to ensure that k is integral. + +// See http://en.wikipedia.org/wiki/Poisson_distribution +// http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html + +#ifndef BOOST_MATH_SPECIAL_POISSON_HPP +#define BOOST_MATH_SPECIAL_POISSON_HPP + +#include +#include // for incomplete gamma. gamma_q +#include // complements +#include // error checks +#include // isnan. +#include // factorials. +#include // for root finding. +#include + +#include + +namespace boost +{ + namespace math + { + namespace detail{ + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + template + inline typename Dist::value_type + inverse_discrete_quantile( + const Dist& dist, + const typename Dist::value_type& p, + const typename Dist::value_type& guess, + const typename Dist::value_type& multiplier, + const typename Dist::value_type& adder, + const policies::discrete_quantile&, + boost::uintmax_t& max_iter); + } + namespace poisson_detail + { + // Common error checking routines for Poisson distribution functions. + // These are convoluted, & apparently redundant, to try to ensure that + // checks are always performed, even if exceptions are not enabled. + + template + inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol) + { + if(!(boost::math::isfinite)(mean) || (mean < 0)) + { + *result = policies::raise_domain_error( + function, + "Mean argument is %1%, but must be >= 0 !", mean, pol); + return false; + } + return true; + } // bool check_mean + + template + inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol) + { // mean == 0 is considered an error. + if( !(boost::math::isfinite)(mean) || (mean <= 0)) + { + *result = policies::raise_domain_error( + function, + "Mean argument is %1%, but must be > 0 !", mean, pol); + return false; + } + return true; + } // bool check_mean_NZ + + template + inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol) + { // Only one check, so this is redundant really but should be optimized away. + return check_mean_NZ(function, mean, result, pol); + } // bool check_dist + + template + inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol) + { + if((k < 0) || !(boost::math::isfinite)(k)) + { + *result = policies::raise_domain_error( + function, + "Number of events k argument is %1%, but must be >= 0 !", k, pol); + return false; + } + return true; + } // bool check_k + + template + inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol) + { + if((check_dist(function, mean, result, pol) == false) || + (check_k(function, k, result, pol) == false)) + { + return false; + } + return true; + } // bool check_dist_and_k + + template + inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol) + { // Check 0 <= p <= 1 + if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) + { + *result = policies::raise_domain_error( + function, + "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol); + return false; + } + return true; + } // bool check_prob + + template + inline bool check_dist_and_prob(const char* function, RealType mean, RealType p, RealType* result, const Policy& pol) + { + if((check_dist(function, mean, result, pol) == false) || + (check_prob(function, p, result, pol) == false)) + { + return false; + } + return true; + } // bool check_dist_and_prob + + } // namespace poisson_detail + + template > + class poisson_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + poisson_distribution(RealType mean = 1) : m_l(mean) // mean (lambda). + { // Expected mean number of events that occur during the given interval. + RealType r; + poisson_detail::check_dist( + "boost::math::poisson_distribution<%1%>::poisson_distribution", + m_l, + &r, Policy()); + } // poisson_distribution constructor. + + RealType mean() const + { // Private data getter function. + return m_l; + } + private: + // Data member, initialized by constructor. + RealType m_l; // mean number of occurrences. + }; // template class poisson_distribution + + typedef poisson_distribution poisson; // Reserved name of type double. + + // Non-member functions to give properties of the distribution. + + template + inline const std::pair range(const poisson_distribution& /* dist */) + { // Range of permissible values for random variable k. + using boost::math::tools::max_value; + return std::pair(0, max_value()); // Max integer? + } + + template + inline const std::pair support(const poisson_distribution& /* dist */) + { // Range of supported values for random variable k. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); + } + + template + inline RealType mean(const poisson_distribution& dist) + { // Mean of poisson distribution = lambda. + return dist.mean(); + } // mean + + template + inline RealType mode(const poisson_distribution& dist) + { // mode. + BOOST_MATH_STD_USING // ADL of std functions. + return floor(dist.mean()); + } + + //template + //inline RealType median(const poisson_distribution& dist) + //{ // median = approximately lambda + 1/3 - 0.2/lambda + // RealType l = dist.mean(); + // return dist.mean() + static_cast(0.3333333333333333333333333333333333333333333333) + // - static_cast(0.2) / l; + //} // BUT this formula appears to be out-by-one compared to quantile(half) + // Query posted on Wikipedia. + // Now implemented via quantile(half) in derived accessors. + + template + inline RealType variance(const poisson_distribution& dist) + { // variance. + return dist.mean(); + } + + // RealType standard_deviation(const poisson_distribution& dist) + // standard_deviation provided by derived accessors. + + template + inline RealType skewness(const poisson_distribution& dist) + { // skewness = sqrt(l). + BOOST_MATH_STD_USING // ADL of std functions. + return 1 / sqrt(dist.mean()); + } + + template + inline RealType kurtosis_excess(const poisson_distribution& dist) + { // skewness = sqrt(l). + return 1 / dist.mean(); // kurtosis_excess 1/mean from Wiki & MathWorld eq 31. + // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess + // is more convenient because the kurtosis excess of a normal distribution is zero + // whereas the true kurtosis is 3. + } // RealType kurtosis_excess + + template + inline RealType kurtosis(const poisson_distribution& dist) + { // kurtosis is 4th moment about the mean = u4 / sd ^ 4 + // http://en.wikipedia.org/wiki/Curtosis + // kurtosis can range from -2 (flat top) to +infinity (sharp peak & heavy tails). + // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm + return 3 + 1 / dist.mean(); // NIST. + // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess + // is more convenient because the kurtosis excess of a normal distribution is zero + // whereas the true kurtosis is 3. + } // RealType kurtosis + + template + RealType pdf(const poisson_distribution& dist, const RealType& k) + { // Probability Density/Mass Function. + // Probability that there are EXACTLY k occurrences (or arrivals). + BOOST_FPU_EXCEPTION_GUARD + + BOOST_MATH_STD_USING // for ADL of std functions. + + RealType mean = dist.mean(); + // Error check: + RealType result; + if(false == poisson_detail::check_dist_and_k( + "boost::math::pdf(const poisson_distribution<%1%>&, %1%)", + mean, + k, + &result, Policy())) + { + return result; + } + + // Special case of mean zero, regardless of the number of events k. + if (mean == 0) + { // Probability for any k is zero. + return 0; + } + if (k == 0) + { // mean ^ k = 1, and k! = 1, so can simplify. + return exp(-mean); + } + using boost::math::unchecked_factorial; + RealType floork = floor(k); + if ((floork == k) // integral + && k < max_factorial::value) + { // k is small enough (for float 34, double 170 ...) to use factorial(k). + return exp(-mean) * pow(mean, k) / + unchecked_factorial(tools::real_cast(floork)); + } + else + { // Need to use log(factorial(k)) = lgamma(k+1) + // (e ^ -mean * mean ^ k) / k! + // == exp(log(e ^ -mean) + log (mean ^ k) - lgamma(k+1)) + // exp( -mean + log(mean) * k - lgamma(k+1)) + return exp(-mean + log(mean) * k - boost::math::lgamma(k+1, Policy())); + // return gamma_p_derivative(k+1, mean); // equivalent & also passes tests. + } + } // pdf + + template + RealType cdf(const poisson_distribution& dist, const RealType& k) + { // Cumulative Distribution Function Poisson. + // The random variate k is the number of occurrences(or arrivals) + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + // Returns the sum of the terms 0 through k of the Poisson Probability Density or Mass (pdf). + + // But note that the Poisson distribution + // (like others including the binomial, negative binomial & Bernoulli) + // is strictly defined as a discrete function: only integral values of k are envisaged. + // However because of the method of calculation using a continuous gamma function, + // it is convenient to treat it as if it is a continous function + // and permit non-integral values of k. + // To enforce the strict mathematical model, users should use floor or ceil functions + // outside this function to ensure that k is integral. + + // The terms are not summed directly (at least for larger k) + // instead the incomplete gamma integral is employed, + + BOOST_MATH_STD_USING // for ADL of std function exp. + + RealType mean = dist.mean(); + // Error checks: + RealType result; + if(false == poisson_detail::check_dist_and_k( + "boost::math::cdf(const poisson_distribution<%1%>&, %1%)", + mean, + k, + &result, Policy())) + { + return result; + } + // Special cases: + if (mean == 0) + { // Probability for any k is zero. + return 0; + } + if (k == 0) + { // return pdf(dist, static_cast(0)); + // but mean (and k) have already been checked, + // so this avoids unnecessary repeated checks. + return exp(-mean); + } + // For small integral k could use a finite sum - + // it's cheaper than the gamma function. + // BUT this is now done efficiently by gamma_q function. + // Calculate poisson cdf using the gamma_q function. + return gamma_q(k+1, mean, Policy()); + } // binomial cdf + + template + RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function Poisson + // The random variate k is the number of events, occurrences or arrivals. + // k argument may be integral, signed, or unsigned, or floating point. + // If necessary, it has already been promoted from an integral type. + // But note that the Poisson distribution + // (like others including the binomial, negative binomial & Bernoulli) + // is strictly defined as a discrete function: only integral values of k are envisaged. + // However because of the method of calculation using a continuous gamma function, + // it is convenient to treat it as is it is a continous function + // and permit non-integral values of k. + // To enforce the strict mathematical model, users should use floor or ceil functions + // outside this function to ensure that k is integral. + + // Returns the sum of the terms k+1 through inf of the Poisson Probability Density/Mass (pdf). + // The terms are not summed directly (at least for larger k) + // instead the incomplete gamma integral is employed, + + RealType const& k = c.param; + poisson_distribution const& dist = c.dist; + + RealType mean = dist.mean(); + + // Error checks: + RealType result; + if(false == poisson_detail::check_dist_and_k( + "boost::math::cdf(const poisson_distribution<%1%>&, %1%)", + mean, + k, + &result, Policy())) + { + return result; + } + // Special case of mean, regardless of the number of events k. + if (mean == 0) + { // Probability for any k is unity, complement of zero. + return 1; + } + if (k == 0) + { // Avoid repeated checks on k and mean in gamma_p. + return -boost::math::expm1(-mean, Policy()); + } + // Unlike un-complemented cdf (sum from 0 to k), + // can't use finite sum from k+1 to infinity for small integral k, + // anyway it is now done efficiently by gamma_p. + return gamma_p(k + 1, mean, Policy()); // Calculate Poisson cdf using the gamma_p function. + // CCDF = gamma_p(k+1, lambda) + } // poisson ccdf + + template + inline RealType quantile(const poisson_distribution& dist, const RealType& p) + { // Quantile (or Percent Point) Poisson function. + // Return the number of expected events k for a given probability p. + RealType result; // of Argument checks: + if(false == poisson_detail::check_prob( + "boost::math::quantile(const poisson_distribution<%1%>&, %1%)", + p, + &result, Policy())) + { + return result; + } + // Special case: + if (dist.mean() == 0) + { // if mean = 0 then p = 0, so k can be anything? + if (false == poisson_detail::check_mean_NZ( + "boost::math::quantile(const poisson_distribution<%1%>&, %1%)", + dist.mean(), + &result, Policy())) + { + return result; + } + } + /* + BOOST_MATH_STD_USING // ADL of std functions. + // if(p == 0) NOT necessarily zero! + // Not necessarily any special value of k because is unlimited. + if (p <= exp(-dist.mean())) + { // if p <= cdf for 0 events (== pdf for 0 events), then quantile must be zero. + return 0; + } + return gamma_q_inva(dist.mean(), p, Policy()) - 1; + */ + typedef typename Policy::discrete_quantile_type discrete_type; + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + RealType guess, factor = 8; + RealType z = dist.mean(); + if(z < 1) + guess = z; + else + guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, 1-p, Policy()); + if(z > 5) + { + if(z > 1000) + factor = 1.01f; + else if(z > 50) + factor = 1.1f; + else if(guess > 10) + factor = 1.25f; + else + factor = 2; + if(guess < 1.1) + factor = 8; + } + + return detail::inverse_discrete_quantile( + dist, + p, + 1-p, + guess, + factor, + RealType(1), + discrete_type(), + max_iter); + } // quantile + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { // Quantile (or Percent Point) of Poisson function. + // Return the number of expected events k for a given + // complement of the probability q. + // + // Error checks: + RealType q = c.param; + const poisson_distribution& dist = c.dist; + RealType result; // of argument checks. + if(false == poisson_detail::check_prob( + "boost::math::quantile(const poisson_distribution<%1%>&, %1%)", + q, + &result, Policy())) + { + return result; + } + // Special case: + if (dist.mean() == 0) + { // if mean = 0 then p = 0, so k can be anything? + if (false == poisson_detail::check_mean_NZ( + "boost::math::quantile(const poisson_distribution<%1%>&, %1%)", + dist.mean(), + &result, Policy())) + { + return result; + } + } + /* + if (-q <= boost::math::expm1(-dist.mean())) + { // if q <= cdf(complement for 0 events, then quantile must be zero. + return 0; + } + return gamma_p_inva(dist.mean(), q, Policy()) -1; + */ + typedef typename Policy::discrete_quantile_type discrete_type; + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + RealType guess, factor = 8; + RealType z = dist.mean(); + if(z < 1) + guess = z; + else + guess = boost::math::detail::inverse_poisson_cornish_fisher(z, 1-q, q, Policy()); + if(z > 5) + { + if(z > 1000) + factor = 1.01f; + else if(z > 50) + factor = 1.1f; + else if(guess > 10) + factor = 1.25f; + else + factor = 2; + if(guess < 1.1) + factor = 8; + } + + return detail::inverse_discrete_quantile( + dist, + 1-q, + q, + guess, + factor, + RealType(1), + discrete_type(), + max_iter); + } // quantile complement. + + } // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include +#include + +#endif // BOOST_MATH_SPECIAL_POISSON_HPP + + + diff --git a/include/boost/math/distributions/rayleigh.hpp b/include/boost/math/distributions/rayleigh.hpp new file mode 100644 index 000000000..2a97b4194 --- /dev/null +++ b/include/boost/math/distributions/rayleigh.hpp @@ -0,0 +1,293 @@ +// Copyright Paul A. Bristow 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_rayleigh_HPP +#define BOOST_STATS_rayleigh_HPP + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code (return after domain_error throw). +#endif + +#include + +namespace boost{ namespace math{ + +namespace detail +{ // Error checks: + template + inline bool verify_sigma(const char* function, RealType sigma, RealType* presult, const Policy& pol) + { + if(sigma <= 0) + { + *presult = policies::raise_domain_error( + function, + "The scale parameter \"sigma\" must be > 0, but was: %1%.", sigma, pol); + return false; + } + return true; + } // bool verify_sigma + + template + inline bool verify_rayleigh_x(const char* function, RealType x, RealType* presult, const Policy& pol) + { + if(x < 0) + { + *presult = policies::raise_domain_error( + function, + "The random variable must be >= 0, but was: %1%.", x, pol); + return false; + } + return true; + } // bool verify_rayleigh_x +} // namespace detail + +template > +class rayleigh_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + rayleigh_distribution(RealType sigma = 1) + : m_sigma(sigma) + { + RealType err; + detail::verify_sigma("boost::math::rayleigh_distribution<%1%>::rayleigh_distribution", sigma, &err, Policy()); + } // rayleigh_distribution + + RealType sigma()const + { // Accessor. + return m_sigma; + } + +private: + RealType m_sigma; +}; // class rayleigh_distribution + +typedef rayleigh_distribution rayleigh; + +template +inline const std::pair range(const rayleigh_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(static_cast(1), max_value()); +} + +template +inline const std::pair support(const rayleigh_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair((1), max_value()); +} + +template +inline RealType pdf(const rayleigh_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std function exp. + + RealType sigma = dist.sigma(); + RealType result; + static const char* function = "boost::math::pdf(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + if(false == detail::verify_rayleigh_x(function, x, &result, Policy())) + { + return result; + } + RealType sigmasqr = sigma * sigma; + result = x * (exp(-(x * x) / ( 2 * sigmasqr))) / sigmasqr; + return result; +} // pdf + +template +inline RealType cdf(const rayleigh_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType result; + RealType sigma = dist.sigma(); + static const char* function = "boost::math::cdf(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + if(false == detail::verify_rayleigh_x(function, x, &result, Policy())) + { + return result; + } + result = -boost::math::expm1(-x * x / ( 2 * sigma * sigma), Policy()); + return result; +} // cdf + +template +inline RealType quantile(const rayleigh_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType result; + RealType sigma = dist.sigma(); + static const char* function = "boost::math::quantile(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + return result; + if(false == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 0) + { + return 0; + } + if(p == 1) + { + return policies::raise_overflow_error(function, 0, Policy()); + } + result = sqrt(-2 * sigma * sigma * boost::math::log1p(-p, Policy())); + return result; +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + RealType result; + RealType sigma = c.dist.sigma(); + static const char* function = "boost::math::cdf(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + RealType x = c.param; + if(false == detail::verify_rayleigh_x(function, x, &result, Policy())) + { + return result; + } + result = exp(-x * x / ( 2 * sigma * sigma)); + return result; +} // cdf complement + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions, log & sqrt. + + RealType result; + RealType sigma = c.dist.sigma(); + static const char* function = "boost::math::quantile(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + RealType q = c.param; + if(false == detail::check_probability(function, q, &result, Policy())) + { + return result; + } + if(q == 1) + { + return 0; + } + if(q == 0) + { + return policies::raise_overflow_error(function, 0, Policy()); + } + result = sqrt(-2 * sigma * sigma * log(q)); + return result; +} // quantile complement + +template +inline RealType mean(const rayleigh_distribution& dist) +{ + RealType result; + RealType sigma = dist.sigma(); + static const char* function = "boost::math::mean(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + using boost::math::constants::root_half_pi; + return sigma * root_half_pi(); +} // mean + +template +inline RealType variance(const rayleigh_distribution& dist) +{ + RealType result; + RealType sigma = dist.sigma(); + static const char* function = "boost::math::variance(const rayleigh_distribution<%1%>&, %1%)"; + if(false == detail::verify_sigma(function, sigma, &result, Policy())) + { + return result; + } + using boost::math::constants::four_minus_pi; + return four_minus_pi() * sigma * sigma / 2; +} // variance + +template +inline RealType mode(const rayleigh_distribution& dist) +{ + return dist.sigma(); +} + +template +inline RealType median(const rayleigh_distribution& dist) +{ + using boost::math::constants::root_ln_four; + return root_ln_four() * dist.sigma(); +} + +template +inline RealType skewness(const rayleigh_distribution& /*dist*/) +{ + // using namespace boost::math::constants; + return static_cast(0.63111065781893713819189935154422777984404221106391L); + // Computed using NTL at 150 bit, about 50 decimal digits. + // return 2 * root_pi() * pi_minus_three() / pow23_four_minus_pi(); +} + +template +inline RealType kurtosis(const rayleigh_distribution& /*dist*/) +{ + // using namespace boost::math::constants; + return static_cast(3.2450893006876380628486604106197544154170667057995L); + // Computed using NTL at 150 bit, about 50 decimal digits. + // return 3 - (6 * pi() * pi() - 24 * pi() + 16) / + // (four_minus_pi() * four_minus_pi()); +} + +template +inline RealType kurtosis_excess(const rayleigh_distribution& /*dist*/) +{ + //using namespace boost::math::constants; + // Computed using NTL at 150 bit, about 50 decimal digits. + return static_cast(0.2450893006876380628486604106197544154170667057995L); + // return -(6 * pi() * pi() - 24 * pi() + 16) / + // (four_minus_pi() * four_minus_pi()); +} // kurtosis + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_rayleigh_HPP diff --git a/include/boost/math/distributions/students_t.hpp b/include/boost/math/distributions/students_t.hpp new file mode 100644 index 000000000..14bdf9cfe --- /dev/null +++ b/include/boost/math/distributions/students_t.hpp @@ -0,0 +1,374 @@ +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_STUDENTS_T_HPP +#define BOOST_STATS_STUDENTS_T_HPP + +// http://en.wikipedia.org/wiki/Student%27s_t_distribution +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3664.htm + +#include +#include // for ibeta(a, b, x). +#include +#include + +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code (return after domain_error throw). +#endif + +namespace boost{ namespace math{ + +template > +class students_t_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + students_t_distribution(RealType i) : m_df(i) + { // Constructor. + RealType result; + detail::check_df( + "boost::math::students_t_distribution<%1%>::students_t_distribution", m_df, &result, Policy()); + } // students_t_distribution + + RealType degrees_of_freedom()const + { + return m_df; + } + + // Parameter estimation: + static RealType find_degrees_of_freedom( + RealType difference_from_mean, + RealType alpha, + RealType beta, + RealType sd, + RealType hint = 100); + +private: + // + // Data members: + // + RealType m_df; // degrees of freedom are a real number. +}; + +typedef students_t_distribution students_t; + +template +inline const std::pair range(const students_t_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); +} + +template +inline const std::pair support(const students_t_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); +} + +template +inline RealType pdf(const students_t_distribution& dist, const RealType& t) +{ + BOOST_FPU_EXCEPTION_GUARD + BOOST_MATH_STD_USING // for ADL of std functions + + RealType degrees_of_freedom = dist.degrees_of_freedom(); + // Error check: + RealType error_result; + if(false == detail::check_df( + "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", degrees_of_freedom, &error_result, Policy())) + return error_result; + // Might conceivably permit df = +infinity and use normal distribution. + RealType result; + RealType basem1 = t * t / degrees_of_freedom; + if(basem1 < 0.125) + { + result = exp(-boost::math::log1p(basem1, Policy()) * (1+degrees_of_freedom) / 2); + } + else + { + result = pow(1 / (1 + basem1), (degrees_of_freedom + 1) / 2); + } + result /= sqrt(degrees_of_freedom) * boost::math::beta(degrees_of_freedom / 2, RealType(0.5f), Policy()); + return result; +} // pdf + +template +inline RealType cdf(const students_t_distribution& dist, const RealType& t) +{ + RealType degrees_of_freedom = dist.degrees_of_freedom(); + // Error check: + RealType error_result; + if(false == detail::check_df( + "boost::math::cdf(const students_t_distribution<%1%>&, %1%)", degrees_of_freedom, &error_result, Policy())) + return error_result; + + if (t == 0) + { + return 0.5; + } + // + // Calculate probability of Student's t using the incomplete beta function. + // probability = ibeta(degrees_of_freedom / 2, 1/2, degrees_of_freedom / (degrees_of_freedom + t*t)) + // + // However when t is small compared to the degrees of freedom, that formula + // suffers from rounding error, use the identity formula to work around + // the problem: + // + // I[x](a,b) = 1 - I[1-x](b,a) + // + // and: + // + // x = df / (df + t^2) + // + // so: + // + // 1 - x = t^2 / (df + t^2) + // + RealType t2 = t * t; + RealType probability; + if(degrees_of_freedom > 2 * t2) + { + RealType z = t2 / (degrees_of_freedom + t2); + probability = ibetac(static_cast(0.5), degrees_of_freedom / 2, z, Policy()) / 2; + } + else + { + RealType z = degrees_of_freedom / (degrees_of_freedom + t2); + probability = ibeta(degrees_of_freedom / 2, static_cast(0.5), z, Policy()) / 2; + } + return (t > 0 ? 1 - probability : probability); +} // cdf + +template +inline RealType quantile(const students_t_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + // + // Obtain parameters: + // + RealType degrees_of_freedom = dist.degrees_of_freedom(); + RealType probability = p; + // + // Check for domain errors: + // + static const char* function = "boost::math::quantile(const students_t_distribution<%1%>&, %1%)"; + RealType error_result; + if(false == detail::check_df( + function, degrees_of_freedom, &error_result, Policy()) + && detail::check_probability(function, probability, &error_result, Policy())) + return error_result; + + // Special cases, regardless of degrees_of_freedom. + if (probability == 0) + return -policies::raise_overflow_error(function, 0, Policy()); + if (probability == 1) + return policies::raise_overflow_error(function, 0, Policy()); + if (probability == static_cast(0.5)) + return 0; + // + // This next block is disabled in favour of a faster method than + // incomplete beta inverse, code retained for future reference: + // +#if 0 + // + // Calculate quantile of Student's t using the incomplete beta function inverse: + // + probability = (probability > 0.5) ? 1 - probability : probability; + RealType t, x, y; + x = ibeta_inv(degrees_of_freedom / 2, RealType(0.5), 2 * probability, &y); + if(degrees_of_freedom * y > tools::max_value() * x) + t = tools::overflow_error(function); + else + t = sqrt(degrees_of_freedom * y / x); + // + // Figure out sign based on the size of p: + // + if(p < 0.5) + t = -t; + + return t; +#endif + // + // Depending on how many digits RealType has, this may forward + // to the incomplete beta inverse as above. Otherwise uses a + // faster method that is accurate to ~15 digits everywhere + // and a couple of epsilon at double precision and in the central + // region where most use cases will occur... + // + return boost::math::detail::fast_students_t_quantile(degrees_of_freedom, probability, Policy()); +} // quantile + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + return cdf(c.dist, -c.param); +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + return -quantile(c.dist, c.param); +} + +// +// Parameter estimation follows: +// +namespace detail{ +// +// Functors for finding degrees of freedom: +// +template +struct sample_size_func +{ + sample_size_func(RealType a, RealType b, RealType s, RealType d) + : alpha(a), beta(b), ratio(s*s/(d*d)) {} + + RealType operator()(const RealType& df) + { + if(df <= tools::min_value()) + return 1; + students_t_distribution t(df); + RealType qa = quantile(complement(t, alpha)); + RealType qb = quantile(complement(t, beta)); + qa += qb; + qa *= qa; + qa *= ratio; + qa -= (df + 1); + return qa; + } + RealType alpha, beta, ratio; +}; + +} // namespace detail + +template +RealType students_t_distribution::find_degrees_of_freedom( + RealType difference_from_mean, + RealType alpha, + RealType beta, + RealType sd, + RealType hint) +{ + static const char* function = "boost::math::students_t_distribution<%1%>::find_degrees_of_freedom"; + // + // Check for domain errors: + // + RealType error_result; + if(false == detail::check_probability( + function, alpha, &error_result, Policy()) + && detail::check_probability(function, beta, &error_result, Policy())) + return error_result; + + if(hint <= 0) + hint = 1; + + detail::sample_size_func f(alpha, beta, sd, difference_from_mean); + tools::eps_tolerance tol(policies::digits()); + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + std::pair r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy()); + RealType result = r.first + (r.second - r.first) / 2; + if(max_iter == policies::get_max_root_iterations()) + { + policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" + " either there is no answer to how many degrees of freedom are required" + " or the answer is infinite. Current best guess is %1%", result, Policy()); + } + return result; +} + +template +inline RealType mean(const students_t_distribution& ) +{ + return 0; +} + +template +inline RealType variance(const students_t_distribution& dist) +{ + // Error check: + RealType error_result; + if(false == detail::check_df( + "boost::math::variance(students_t_distribution<%1%> const&, %1%)", dist.degrees_of_freedom(), &error_result, Policy())) + return error_result; + + RealType v = dist.degrees_of_freedom(); + return v / (v - 2); +} + +template +inline RealType mode(const students_t_distribution& /*dist*/) +{ + return 0; +} + +template +inline RealType median(const students_t_distribution& /*dist*/) +{ + return 0; +} + +template +inline RealType skewness(const students_t_distribution& dist) +{ + if(dist.degrees_of_freedom() <= 3) + { + policies::raise_domain_error( + "boost::math::skewness(students_t_distribution<%1%> const&, %1%)", + "Skewness is undefined for degrees of freedom <= 3, but got %1%.", + dist.degrees_of_freedom(), Policy()); + } + return 0; +} + +template +inline RealType kurtosis(const students_t_distribution& dist) +{ + RealType df = dist.degrees_of_freedom(); + if(df <= 3) + { + policies::raise_domain_error( + "boost::math::kurtosis(students_t_distribution<%1%> const&, %1%)", + "Skewness is undefined for degrees of freedom <= 3, but got %1%.", + df, Policy()); + } + return 3 * (df - 2) / (df - 4); +} + +template +inline RealType kurtosis_excess(const students_t_distribution& dist) +{ + // see http://mathworld.wolfram.com/Kurtosis.html + RealType df = dist.degrees_of_freedom(); + if(df <= 3) + { + policies::raise_domain_error( + "boost::math::kurtosis_excess(students_t_distribution<%1%> const&, %1%)", + "Skewness is undefined for degrees of freedom <= 3, but got %1%.", + df, Policy()); + } + return 6 / (df - 4); +} + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_STUDENTS_T_HPP diff --git a/include/boost/math/distributions/triangular.hpp b/include/boost/math/distributions/triangular.hpp new file mode 100644 index 000000000..a23853ea1 --- /dev/null +++ b/include/boost/math/distributions/triangular.hpp @@ -0,0 +1,521 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2006, 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_TRIANGULAR_HPP +#define BOOST_STATS_TRIANGULAR_HPP + +// http://mathworld.wolfram.com/TriangularDistribution.html +// http://en.wikipedia.org/wiki/Triangular_distribution + +#include +#include +#include +#include +#include + +#include + +namespace boost{ namespace math +{ + namespace detail + { + template + inline bool check_triangular_lower( + const char* function, + RealType lower, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(lower)) + { // Any finite value is OK. + return true; + } + else + { // Not finite: infinity or NaN. + *result = policies::raise_domain_error( + function, + "Lower parameter is %1%, but must be finite!", lower, pol); + return false; + } + } // bool check_triangular_lower( + + template + inline bool check_triangular_mode( + const char* function, + RealType mode, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(mode)) + { // any finite value is OK. + return true; + } + else + { // Not finite: infinity or NaN. + *result = policies::raise_domain_error( + function, + "Mode parameter is %1%, but must be finite!", mode, pol); + return false; + } + } // bool check_triangular_mode( + + template + inline bool check_triangular_upper( + const char* function, + RealType upper, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(upper)) + { // any finite value is OK. + return true; + } + else + { // Not finite: infinity or NaN. + *result = policies::raise_domain_error( + function, + "Upper parameter is %1%, but must be finite!", upper, pol); + return false; + } + } // bool check_triangular_upper( + + template + inline bool check_triangular_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(x)) + { // Any finite value is OK + return true; + } + else + { // Not finite: infinity or NaN. + *result = policies::raise_domain_error( + function, + "x parameter is %1%, but must be finite!", x, pol); + return false; + } + } // bool check_triangular_x + + template + inline bool check_triangular( + const char* function, + RealType lower, + RealType mode, + RealType upper, + RealType* result, const Policy& pol) + { + if(check_triangular_lower(function, lower, result, pol) + && check_triangular_mode(function, mode, result, pol) + && check_triangular_upper(function, upper, result, pol) + && (lower < upper) // lower == upper NOT useful. + ) + { + if (mode < lower) + { + *result = policies::raise_domain_error( + function, + "mode parameter is %1%, but must be >= than lower!", lower, pol); + return false; + } + if (mode > upper ) + { + *result = policies::raise_domain_error( + function, + "mode parameter is %1%, but must be <= than upper!", upper, pol); + return false; + } + return true; + } + else + { // upper and lower have each been checked before, so must be lower >= upper. + *result = policies::raise_domain_error( + function, + "lower parameter is %1%, but must be less than upper!", lower, pol); + return false; + } + } // bool check_triangular + } // namespace detail + + template > + class triangular_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + triangular_distribution(RealType lower = -1, RealType mode = 0, RealType upper = 1) + : m_lower(lower), m_mode(mode), m_upper(upper) // Constructor. + { // Evans says 'standard triangular' is lower 0, mode 1/2, upper 1, + // has median sqrt(c/2) for c <=1/2 and 1 - sqrt(1-c)/2 for c >= 1/2 + // But this -1, 0, 1 is more useful in most applications to approximate normal distribution, + // where the central value is the most likely and deviations either side equally likely. + RealType result; + detail::check_triangular("boost::math::triangular_distribution<%1%>::triangular_distribution",lower, mode, upper, &result, Policy()); + } + // Accessor functions. + RealType lower()const + { + return m_lower; + } + RealType mode()const + { + return m_mode; + } + RealType upper()const + { + return m_upper; + } + private: + // Data members: + RealType m_lower; // distribution lower aka a + RealType m_mode; // distribution mode aka c + RealType m_upper; // distribution upper aka b + }; // class triangular_distribution + + typedef triangular_distribution triangular; + + template + inline const std::pair range(const triangular_distribution& /* dist */) + { // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); + } + + template + inline const std::pair support(const triangular_distribution& dist) + { // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + return std::pair(dist.lower(), dist.upper()); + } + + template + RealType pdf(const triangular_distribution& dist, const RealType& x) + { + static const char* function = "boost::math::pdf(const triangular_distribution<%1%>&, %1%)"; + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_triangular_x(function, x, &result, Policy())) + { + return result; + } + if((x < lower) || (x > upper)) + { + return 0; + } + if (x == lower) + { // (mode - lower) == 0 which would lead to divide by zero! + return (mode == lower) ? 2 / (upper - lower) : 0; + } + else if (x == upper) + { + return (mode == upper) ? 2 / (upper - lower) : 0; + } + else if (x <= mode) + { + return 2 * (x - lower) / ((upper - lower) * (mode - lower)); + } + else + { // (x > mode) + return 2 * (upper - x) / ((upper - lower) * (upper - mode)); + } + } // RealType pdf(const triangular_distribution& dist, const RealType& x) + + template + inline RealType cdf(const triangular_distribution& dist, const RealType& x) + { + static const char* function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)"; + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_triangular_x(function, x, &result, Policy())) + { + return result; + } + if((x <= lower)) + { + return 0; + } + if (x >= upper) + { + return 1; + } + // else lower < x < upper + if (x <= mode) + { + return ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower)); + } + else + { + return 1 - (upper - x) * (upper - x) / ((upper - lower) * (upper - mode)); + } + } // RealType cdf(const triangular_distribution& dist, const RealType& x) + + template + RealType quantile(const triangular_distribution& dist, const RealType& p) + { + BOOST_MATH_STD_USING // for ADL of std functions (sqrt). + static const char* function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)"; + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks + if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_probability(function, p, &result, Policy())) + { + return result; + } + if(p == 0) + { + return lower; + } + if(p == 1) + { + return upper; + } + RealType p0 = (mode - lower) / (upper - lower); + RealType q = 1 - p; + if (p < p0) + { + result = sqrt((upper - lower) * (mode - lower) * p) + lower; + } + else if (p == p0) + { + result = mode; + } + else // p > p0 + { + result = upper - sqrt((upper - lower) * (upper - mode) * q); + } + return result; + + } // RealType quantile(const triangular_distribution& dist, const RealType& q) + + template + RealType cdf(const complemented2_type, RealType>& c) + { + static const char* function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)"; + RealType lower = c.dist.lower(); + RealType mode = c.dist.mode(); + RealType upper = c.dist.upper(); + RealType x = c.param; + RealType result; // of checks. + if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_triangular_x(function, x, &result, Policy())) + { + return result; + } + if (x <= lower) + { + return 1; + } + if (x >= upper) + { + return 0; + } + if (x <= mode) + { + return 1 - ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower)); + } + else + { + return (upper - x) * (upper - x) / ((upper - lower) * (upper - mode)); + } + } // RealType cdf(const complemented2_type, RealType>& c) + + template + RealType quantile(const complemented2_type, RealType>& c) + { + BOOST_MATH_STD_USING // Aid ADL for sqrt. + static const char* function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)"; + RealType l = c.dist.lower(); + RealType m = c.dist.mode(); + RealType u = c.dist.upper(); + RealType q = c.param; // probability 0 to 1. + RealType result; // of checks. + if(false == detail::check_triangular(function, l, m, u, &result, Policy())) + { + return result; + } + if(false == detail::check_probability(function, q, &result, Policy())) + { + return result; + } + if(q == 0) + { + return u; + } + if(q == 1) + { + return l; + } + RealType lower = c.dist.lower(); + RealType mode = c.dist.mode(); + RealType upper = c.dist.upper(); + + RealType p = 1 - q; + RealType p0 = (mode - lower) / (upper - lower); + if(p < p0) + { + RealType s = (upper - lower) * (mode - lower); + s *= p; + result = sqrt((upper - lower) * (mode - lower) * p) + lower; + } + else if (p == p0) + { + result = mode; + } + else // p > p0 + { + result = upper - sqrt((upper - lower) * (upper - mode) * q); + } + return result; + } // RealType quantile(const complemented2_type, RealType>& c) + + template + inline RealType mean(const triangular_distribution& dist) + { + static const char* function = "boost::math::mean(const triangular_distribution<%1%>&)"; + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy())) + { + return result; + } + return (lower + upper + mode) / 3; + } // RealType mean(const triangular_distribution& dist) + + + template + inline RealType variance(const triangular_distribution& dist) + { + static const char* function = "boost::math::mean(const triangular_distribution<%1%>&)"; + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy())) + { + return result; + } + return (lower * lower + upper * upper + mode * mode - lower * upper - lower * mode - upper * mode) / 18; + } // RealType variance(const triangular_distribution& dist) + + template + inline RealType mode(const triangular_distribution& dist) + { + static const char* function = "boost::math::mode(const triangular_distribution<%1%>&)"; + RealType mode = dist.mode(); + RealType result; // of checks. + if(false == detail::check_triangular_mode(function, mode, &result, Policy())) + { // This should never happen! + return result; + } + return mode; + } // RealType mode + + template + inline RealType median(const triangular_distribution& dist) + { + BOOST_MATH_STD_USING // ADL of std functions. + static const char* function = "boost::math::median(const triangular_distribution<%1%>&)"; + RealType mode = dist.mode(); + RealType result; // of checks. + if(false == detail::check_triangular_mode(function, mode, &result, Policy())) + { // This should never happen! + return result; + } + RealType lower = dist.lower(); + RealType upper = dist.upper(); + if (mode < (upper - lower) / 2) + { + return lower + sqrt((upper - lower) * (mode - lower)) / constants::root_two(); + } + else + { + return upper - sqrt((upper - lower) * (upper - mode)) / constants::root_two(); + } + } // RealType mode + + template + inline RealType skewness(const triangular_distribution& dist) + { + BOOST_MATH_STD_USING // for ADL of std functions + using namespace boost::math::constants; // for root_two + static const char* function = "boost::math::skewness(const triangular_distribution<%1%>&)"; + + RealType lower = dist.lower(); + RealType mode = dist.mode(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy())) + { + return result; + } + return root_two() * (lower + upper - 2 * mode) * (2 * lower - upper - mode) * (lower - 2 * upper + mode) / + (5 * pow((lower * lower + upper + upper + mode * mode - lower * upper - lower * mode - upper * mode), RealType(3)/RealType(2))); + } // RealType skewness(const triangular_distribution& dist) + + template + inline RealType kurtosis(const triangular_distribution& dist) + { // These checks may be belt and braces as should have been checked on construction? + static const char* function = "boost::math::kurtosis(const triangular_distribution<%1%>&)"; + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType mode = dist.mode(); + RealType result; // of checks. + if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy())) + { + return result; + } + return static_cast(12)/5; // 12/5 = 2.4; + } // RealType kurtosis_excess(const triangular_distribution& dist) + + template + inline RealType kurtosis_excess(const triangular_distribution& dist) + { // These checks may be belt and braces as should have been checked on construction? + static const char* function = "boost::math::kurtosis_excess(const triangular_distribution<%1%>&)"; + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType mode = dist.mode(); + RealType result; // of checks. + if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy())) + { + return result; + } + return static_cast(-3)/5; // - 3/5 = -0.6 + // Assuming mathworld really means kurtosis excess? Wikipedia now corrected to match this. + } + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_TRIANGULAR_HPP + + + diff --git a/include/boost/math/distributions/uniform.hpp b/include/boost/math/distributions/uniform.hpp new file mode 100644 index 000000000..5efb5dd0e --- /dev/null +++ b/include/boost/math/distributions/uniform.hpp @@ -0,0 +1,375 @@ +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// TODO deal with infinity as special better - or remove. +// + +#ifndef BOOST_STATS_UNIFORM_HPP +#define BOOST_STATS_UNIFORM_HPP + +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3668.htm +// http://mathworld.wolfram.com/UniformDistribution.html +// http://documents.wolfram.com/calculationcenter/v2/Functions/ListsMatrices/Statistics/UniformDistribution.html +// http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 + +#include +#include +#include + +#include + +namespace boost{ namespace math +{ + namespace detail + { + template + inline bool check_uniform_lower( + const char* function, + RealType lower, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(lower)) + { // any finite value is OK. + return true; + } + else + { // Not finite. + *result = policies::raise_domain_error( + function, + "Lower parameter is %1%, but must be finite!", lower, pol); + return false; + } + } // bool check_uniform_lower( + + template + inline bool check_uniform_upper( + const char* function, + RealType upper, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(upper)) + { // Any finite value is OK. + return true; + } + else + { // Not finite. + *result = policies::raise_domain_error( + function, + "Upper parameter is %1%, but must be finite!", upper, pol); + return false; + } + } // bool check_uniform_upper( + + template + inline bool check_uniform_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) + { + if((boost::math::isfinite)(x)) + { // Any finite value is OK + return true; + } + else + { // Not finite.. + *result = policies::raise_domain_error( + function, + "x parameter is %1%, but must be finite!", x, pol); + return false; + } + } // bool check_uniform_x + + template + inline bool check_uniform( + const char* function, + RealType lower, + RealType upper, + RealType* result, const Policy& pol) + { + if(check_uniform_lower(function, lower, result, pol) + && check_uniform_upper(function, upper, result, pol) + && (lower < upper)) // If lower == upper then 1 / (upper-lower) = 1/0 = +infinity! + { + return true; + } + else + { // upper and lower have been checked before, so must be lower >= upper. + *result = policies::raise_domain_error( + function, + "lower parameter is %1%, but must be less than upper!", lower, pol); + return false; + } + } // bool check_uniform( + + } // namespace detail + + template > + class uniform_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + uniform_distribution(RealType lower = 0, RealType upper = 1) // Constructor. + : m_lower(lower), m_upper(upper) // Default is standard uniform distribution. + { + RealType result; + detail::check_uniform("boost::math::uniform_distribution<%1%>::uniform_distribution", lower, upper, &result, Policy()); + } + // Accessor functions. + RealType lower()const + { + return m_lower; + } + + RealType upper()const + { + return m_upper; + } + private: + // Data members: + RealType m_lower; // distribution lower aka a. + RealType m_upper; // distribution upper aka b. + }; // class uniform_distribution + + typedef uniform_distribution uniform; + + template + inline const std::pair range(const uniform_distribution& /* dist */) + { // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(-max_value(), max_value()); // - to + infinity + } + + template + inline const std::pair support(const uniform_distribution& dist) + { // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(dist.lower(), dist.upper()); + } + + template + inline RealType pdf(const uniform_distribution& dist, const RealType& x) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::pdf(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_uniform_x("boost::math::pdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy())) + { + return result; + } + + if((x < lower) || (x > upper) ) + { + return 0; + } + else + { + return 1 / (upper - lower); + } + } // RealType pdf(const uniform_distribution& dist, const RealType& x) + + template + inline RealType cdf(const uniform_distribution& dist, const RealType& x) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::cdf(const uniform_distribution<%1%>&, %1%)",lower, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_uniform_x("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy())) + { + return result; + } + if (x < lower) + { + return 0; + } + if (x > upper) + { + return 1; + } + return (x - lower) / (upper - lower); // lower <= x <= upper + } // RealType cdf(const uniform_distribution& dist, const RealType& x) + + template + inline RealType quantile(const uniform_distribution& dist, const RealType& p) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks + if(false == detail::check_uniform("boost::math::quantile(const uniform_distribution<%1%>&, %1%)",lower, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_probability("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", p, &result, Policy())) + { + return result; + } + if(p == 0) + { + return lower; + } + if(p == 1) + { + return upper; + } + return p * (upper - lower) + lower; + } // RealType quantile(const uniform_distribution& dist, const RealType& p) + + template + inline RealType cdf(const complemented2_type, RealType>& c) + { + RealType lower = c.dist.lower(); + RealType upper = c.dist.upper(); + RealType x = c.param; + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_uniform_x("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy())) + { + return result; + } + if (x < lower) + { + return 0; + } + if (x > upper) + { + return 1; + } + return (upper - x) / (upper - lower); + } // RealType cdf(const complemented2_type, RealType>& c) + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { + RealType lower = c.dist.lower(); + RealType upper = c.dist.upper(); + RealType q = c.param; + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy())) + { + return result; + } + if(false == detail::check_probability("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", q, &result, Policy())) + if(q == 0) + { + return lower; + } + if(q == 1) + { + return upper; + } + return -q * (upper - lower) + upper; + } // RealType quantile(const complemented2_type, RealType>& c) + + template + inline RealType mean(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::mean(const uniform_distribution<%1%>&)", lower, upper, &result, Policy())) + { + return result; + } + return (lower + upper ) / 2; + } // RealType mean(const uniform_distribution& dist) + + template + inline RealType variance(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::variance(const uniform_distribution<%1%>&)", lower, upper, &result, Policy())) + { + return result; + } + return (upper - lower) * ( upper - lower) / 12; + // for standard uniform = 0.833333333333333333333333333333333333333333; + } // RealType variance(const uniform_distribution& dist) + + template + inline RealType mode(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::mode(const uniform_distribution<%1%>&)", lower, upper, &result, Policy())) + { + return result; + } + result = lower; // Any value [lower, upper] but arbitrarily choose lower. + return result; + } + + template + inline RealType median(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::median(const uniform_distribution<%1%>&)", lower, upper, &result, Policy())) + { + return result; + } + return (lower + upper) / 2; // + } + template + inline RealType skewness(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::skewness(const uniform_distribution<%1%>&)",lower, upper, &result, Policy())) + { + return result; + } + return 0; + } // RealType skewness(const uniform_distribution& dist) + + template + inline RealType kurtosis_excess(const uniform_distribution& dist) + { + RealType lower = dist.lower(); + RealType upper = dist.upper(); + RealType result; // of checks. + if(false == detail::check_uniform("boost::math::kurtosis_execess(const uniform_distribution<%1%>&)", lower, upper, &result, Policy())) + { + return result; + } + return static_cast(-6)/5; // -6/5 = -1.2; + } // RealType kurtosis_excess(const uniform_distribution& dist) + + template + inline RealType kurtosis(const uniform_distribution& dist) + { + return kurtosis_excess(dist) + 3; + } + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_UNIFORM_HPP + + + diff --git a/include/boost/math/distributions/weibull.hpp b/include/boost/math/distributions/weibull.hpp new file mode 100644 index 000000000..c41704ba9 --- /dev/null +++ b/include/boost/math/distributions/weibull.hpp @@ -0,0 +1,382 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_STATS_WEIBULL_HPP +#define BOOST_STATS_WEIBULL_HPP + +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3668.htm +// http://mathworld.wolfram.com/WeibullDistribution.html + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost{ namespace math +{ +namespace detail{ + +template +inline bool check_weibull_shape( + const char* function, + RealType shape, + RealType* result, const Policy& pol) +{ + if((shape < 0) || !(boost::math::isfinite)(shape)) + { + *result = policies::raise_domain_error( + function, + "Shape parameter is %1%, but must be > 0 !", shape, pol); + return false; + } + return true; +} + +template +inline bool check_weibull_x( + const char* function, + RealType const& x, + RealType* result, const Policy& pol) +{ + if((x < 0) || !(boost::math::isfinite)(x)) + { + *result = policies::raise_domain_error( + function, + "Random variate is %1% but must be >= 0 !", x, pol); + return false; + } + return true; +} + +template +inline bool check_weibull( + const char* function, + RealType scale, + RealType shape, + RealType* result, const Policy& pol) +{ + return check_scale(function, scale, result, pol) && check_weibull_shape(function, shape, result, pol); +} + +} // namespace detail + +template > +class weibull_distribution +{ +public: + typedef RealType value_type; + typedef Policy policy_type; + + weibull_distribution(RealType shape, RealType scale = 1) + : m_shape(shape), m_scale(scale) + { + RealType result; + detail::check_weibull("boost::math::weibull_distribution<%1%>::weibull_distribution", scale, shape, &result, Policy()); + } + + RealType shape()const + { + return m_shape; + } + + RealType scale()const + { + return m_scale; + } +private: + // + // Data members: + // + RealType m_shape; // distribution shape + RealType m_scale; // distribution scale +}; + +typedef weibull_distribution weibull; + +template +inline const std::pair range(const weibull_distribution& /*dist*/) +{ // Range of permissible values for random variable x. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline const std::pair support(const weibull_distribution& /*dist*/) +{ // Range of supported values for random variable x. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(0, max_value()); +} + +template +inline RealType pdf(const weibull_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::pdf(const weibull_distribution<%1%>, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_weibull_x(function, x, &result, Policy())) + return result; + + if(x == 0) + return 0; + + result = exp(-pow(x / scale, shape)); + result *= pow(x / scale, shape) * shape / x; + + return result; +} + +template +inline RealType cdf(const weibull_distribution& dist, const RealType& x) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_weibull_x(function, x, &result, Policy())) + return result; + + result = -boost::math::expm1(-pow(x / scale, shape), Policy()); + + return result; +} + +template +inline RealType quantile(const weibull_distribution& dist, const RealType& p) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_probability(function, p, &result, Policy())) + return result; + + if(p == 1) + return policies::raise_overflow_error(function, 0, Policy()); + + result = scale * pow(-boost::math::log1p(-p, Policy()), 1 / shape); + + return result; +} + +template +inline RealType cdf(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)"; + + RealType shape = c.dist.shape(); + RealType scale = c.dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_weibull_x(function, c.param, &result, Policy())) + return result; + + result = exp(-pow(c.param / scale, shape)); + + return result; +} + +template +inline RealType quantile(const complemented2_type, RealType>& c) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)"; + + RealType shape = c.dist.shape(); + RealType scale = c.dist.scale(); + RealType q = c.param; + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + if(false == detail::check_probability(function, q, &result, Policy())) + return result; + + if(q == 0) + return policies::raise_overflow_error(function, 0, Policy()); + + result = scale * pow(-log(q), 1 / shape); + + return result; +} + +template +inline RealType mean(const weibull_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::mean(const weibull_distribution<%1%>)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + + result = scale * boost::math::tgamma(1 + 1 / shape, Policy()); + return result; +} + +template +inline RealType variance(const weibull_distribution& dist) +{ + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + static const char* function = "boost::math::variance(const weibull_distribution<%1%>)"; + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + { + return result; + } + result = boost::math::tgamma(1 + 1 / shape, Policy()); + result *= -result; + result += boost::math::tgamma(1 + 2 / shape, Policy()); + result *= scale * scale; + return result; +} + +template +inline RealType mode(const weibull_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std function pow. + + static const char* function = "boost::math::mode(const weibull_distribution<%1%>)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + { + return result; + } + result = scale * pow((shape - 1) / shape, 1 / shape); + return result; +} + +template +inline RealType median(const weibull_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std function pow. + + static const char* function = "boost::math::median(const weibull_distribution<%1%>)"; + + RealType shape = dist.shape(); // Wikipedia k + RealType scale = dist.scale(); // Wikipedia lambda + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + { + return result; + } + using boost::math::constants::ln_two; + result = scale * pow(ln_two(), 1 / shape); + return result; +} + +template +inline RealType skewness(const weibull_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::skewness(const weibull_distribution<%1%>)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + { + return result; + } + RealType g1, g2, g3, d; + + g1 = boost::math::tgamma(1 + 1 / shape, Policy()); + g2 = boost::math::tgamma(1 + 2 / shape, Policy()); + g3 = boost::math::tgamma(1 + 3 / shape, Policy()); + d = pow(g2 - g1 * g1, RealType(1.5)); + + result = (2 * g1 * g1 * g1 - 3 * g1 * g2 + g3) / d; + return result; +} + +template +inline RealType kurtosis_excess(const weibull_distribution& dist) +{ + BOOST_MATH_STD_USING // for ADL of std functions + + static const char* function = "boost::math::kurtosis_excess(const weibull_distribution<%1%>)"; + + RealType shape = dist.shape(); + RealType scale = dist.scale(); + + RealType result; + if(false == detail::check_weibull(function, scale, shape, &result, Policy())) + return result; + + RealType g1, g2, g3, g4, d, g1_2, g1_4; + + g1 = boost::math::tgamma(1 + 1 / shape, Policy()); + g2 = boost::math::tgamma(1 + 2 / shape, Policy()); + g3 = boost::math::tgamma(1 + 3 / shape, Policy()); + g4 = boost::math::tgamma(1 + 4 / shape, Policy()); + g1_2 = g1 * g1; + g1_4 = g1_2 * g1_2; + d = g2 - g1_2; + d *= d; + + result = -6 * g1_4 + 12 * g1_2 * g2 - 3 * g2 * g2 - 4 * g1 * g3 + g4; + result /= d; + return result; +} + +template +inline RealType kurtosis(const weibull_distribution& dist) +{ + return kurtosis_excess(dist) + 3; +} + +} // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_STATS_WEIBULL_HPP + + diff --git a/include/boost/math/policies/error_handling.hpp b/include/boost/math/policies/error_handling.hpp new file mode 100644 index 000000000..cc020b6db --- /dev/null +++ b/include/boost/math/policies/error_handling.hpp @@ -0,0 +1,518 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_POLICY_ERROR_HANDLING_HPP +#define BOOST_MATH_POLICY_ERROR_HANDLING_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef BOOST_MSVC +# pragma warning(push) // Quiet warnings in boost/format.hpp +# pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE +# pragma warning(disable: 4512) // assignment operator could not be generated. +// And warnings in error handling: +# pragma warning(disable: 4702) // unreachable code +// Note that this only occurs when the compiler can deduce code is unreachable, +// for example when policy macros are used to ignore errors rather than throw. +#endif +#include + +namespace boost{ namespace math{ + +class evaluation_error : public std::runtime_error +{ +public: + evaluation_error(const std::string& s) : std::runtime_error(s){} +}; + +namespace policies{ +// +// Forward declarations of user error handlers, +// it's up to the user to provide the definition of these: +// +template +T user_domain_error(const char* function, const char* message, const T& val); +template +T user_pole_error(const char* function, const char* message, const T& val); +template +T user_overflow_error(const char* function, const char* message, const T& val); +template +T user_underflow_error(const char* function, const char* message, const T& val); +template +T user_denorm_error(const char* function, const char* message, const T& val); +template +T user_evaluation_error(const char* function, const char* message, const T& val); + +namespace detail +{ +// +// Helper function to avoid binding rvalue to non-const-reference, +// in other words a warning suppression mechansim: +// +template +inline std::string do_format(Formatter f, const Group& g) +{ + return (f % g).str(); +} + +template +void raise_error(const char* function, const char* message) +{ + if(function == 0) + function = "Unknown function"; + if(message == 0) + message = "Cause unknown"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + msg += ": "; + msg += message; + + E e(msg); + boost::throw_exception(e); +} + +template +void raise_error(const char* function, const char* message, const T& val) +{ + if(function == 0) + function = "Unknown function"; + if(message == 0) + message = "Cause unknown"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + msg += ": "; + msg += message; + + int prec = 2 + (boost::math::policies::digits >() * 30103UL) / 100000UL; + msg = do_format(boost::format(msg), boost::io::group(std::setprecision(prec), val)); + + E e(msg); + boost::throw_exception(e); +} + +template +inline T raise_domain_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&) +{ + raise_error(function, message, val); + // we never get here: + return std::numeric_limits::quiet_NaN(); +} + +template +inline T raise_domain_error( + const char* , + const char* , + const T& , + const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&) +{ + // This may or may not do the right thing, but the user asked for the error + // to be ignored so here we go anyway: + return std::numeric_limits::quiet_NaN(); +} + +template +inline T raise_domain_error( + const char* , + const char* , + const T& , + const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&) +{ + errno = EDOM; + // This may or may not do the right thing, but the user asked for the error + // to be silent so here we go anyway: + return std::numeric_limits::quiet_NaN(); +} + +template +inline T raise_domain_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&) +{ + return user_domain_error(function, message, val); +} + +template +inline T raise_pole_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&) +{ + return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>()); +} + +template +inline T raise_pole_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&) +{ + return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>()); +} + +template +inline T raise_pole_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&) +{ + return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>()); +} + +template +inline T raise_pole_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&) +{ + return user_pole_error(function, message, val); +} + +template +inline T raise_overflow_error( + const char* function, + const char* message, + const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&) +{ + raise_error(function, message ? message : "numeric overflow"); + // we never get here: + return std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : boost::math::tools::max_value(); +} + +template +inline T raise_overflow_error( + const char* , + const char* , + const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&) +{ + // This may or may not do the right thing, but the user asked for the error + // to be ignored so here we go anyway: + return std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : boost::math::tools::max_value(); +} + +template +inline T raise_overflow_error( + const char* , + const char* , + const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&) +{ + errno = ERANGE; + // This may or may not do the right thing, but the user asked for the error + // to be silent so here we go anyway: + return std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : boost::math::tools::max_value(); +} + +template +inline T raise_overflow_error( + const char* function, + const char* message, + const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&) +{ + return user_overflow_error(function, message, std::numeric_limits::infinity()); +} + +template +inline T raise_underflow_error( + const char* function, + const char* message, + const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&) +{ + raise_error(function, message ? message : "numeric underflow"); + // we never get here: + return 0; +} + +template +inline T raise_underflow_error( + const char* , + const char* , + const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&) +{ + // This may or may not do the right thing, but the user asked for the error + // to be ignored so here we go anyway: + return T(0); +} + +template +inline T raise_underflow_error( + const char* /* function */, + const char* /* message */, + const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&) +{ + errno = ERANGE; + // This may or may not do the right thing, but the user asked for the error + // to be silent so here we go anyway: + return T(0); +} + +template +inline T raise_underflow_error( + const char* function, + const char* message, + const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&) +{ + return user_underflow_error(function, message, T(0)); +} + +template +inline T raise_denorm_error( + const char* function, + const char* message, + const T& /* val */, + const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&) +{ + raise_error(function, message ? message : "denormalised result"); + // we never get here: + return T(0); +} + +template +inline T raise_denorm_error( + const char* , + const char* , + const T& val, + const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&) +{ + // This may or may not do the right thing, but the user asked for the error + // to be ignored so here we go anyway: + return val; +} + +template +inline T raise_denorm_error( + const char* , + const char* , + const T& val, + const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&) +{ + errno = ERANGE; + // This may or may not do the right thing, but the user asked for the error + // to be silent so here we go anyway: + return val; +} + +template +inline T raise_denorm_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&) +{ + return user_denorm_error(function, message, val); +} + +template +inline T raise_evaluation_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&) +{ + raise_error(function, message, val); + // we never get here: + return T(0); +} + +template +inline T raise_evaluation_error( + const char* , + const char* , + const T& val, + const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&) +{ + // This may or may not do the right thing, but the user asked for the error + // to be ignored so here we go anyway: + return val; +} + +template +inline T raise_evaluation_error( + const char* , + const char* , + const T& val, + const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&) +{ + errno = EDOM; + // This may or may not do the right thing, but the user asked for the error + // to be silent so here we go anyway: + return val; +} + +template +inline T raise_evaluation_error( + const char* function, + const char* message, + const T& val, + const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&) +{ + return user_evaluation_error(function, message, val); +} + +} // namespace detail + +template +inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&) +{ + typedef typename Policy::domain_error_type policy_type; + return detail::raise_domain_error( + function, message ? message : "Domain Error evaluating function at %1%", + val, policy_type()); +} + +template +inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&) +{ + typedef typename Policy::pole_error_type policy_type; + return detail::raise_pole_error( + function, message ? message : "Evaluation of function at pole %1%", + val, policy_type()); +} + +template +inline T raise_overflow_error(const char* function, const char* message, const Policy&) +{ + typedef typename Policy::overflow_error_type policy_type; + return detail::raise_overflow_error( + function, message ? message : "Overflow Error", + policy_type()); +} + +template +inline T raise_underflow_error(const char* function, const char* message, const Policy&) +{ + typedef typename Policy::underflow_error_type policy_type; + return detail::raise_underflow_error( + function, message ? message : "Underflow Error", + policy_type()); +} + +template +inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&) +{ + typedef typename Policy::denorm_error_type policy_type; + return detail::raise_denorm_error( + function, message ? message : "Denorm Error", + val, + policy_type()); +} + +template +inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&) +{ + typedef typename Policy::evaluation_error_type policy_type; + return detail::raise_evaluation_error( + function, message ? message : "Internal Evaluation Error, best value so far was %1%", + val, policy_type()); +} + +// +// checked_narrowing_cast: +// +namespace detail +{ + +template +inline bool check_overflow(T val, R* result, const char* function, const Policy& pol) +{ + BOOST_MATH_STD_USING + if(fabs(val) > tools::max_value()) + { + *result = static_cast(boost::math::policies::detail::raise_overflow_error(function, 0, pol)); + return true; + } + return false; +} +template +inline bool check_underflow(T val, R* result, const char* function, const Policy& pol) +{ + if((val != 0) && (static_cast(val) == 0)) + { + *result = static_cast(boost::math::policies::detail::raise_underflow_error(function, 0, pol)); + return true; + } + return false; +} +template +inline bool check_denorm(T val, R* result, const char* function, const Policy& pol) +{ + BOOST_MATH_STD_USING + if((fabs(val) < static_cast(tools::min_value())) && (static_cast(val) != 0)) + { + *result = static_cast(boost::math::policies::detail::raise_denorm_error(function, 0, static_cast(val), pol)); + return true; + } + return false; +} + +// Default instantiations with ignore_error policy. +template +inline bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error&){ return false; } +template +inline bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error&){ return false; } +template +inline bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error&){ return false; } + +} // namespace detail + +template +inline R checked_narrowing_cast(T val, const char* function) +{ + typedef typename Policy::overflow_error_type overflow_type; + typedef typename Policy::underflow_error_type underflow_type; + typedef typename Policy::denorm_error_type denorm_type; + // + // Most of what follows will evaluate to a no-op: + // + R result; + if(detail::check_overflow(val, &result, function, overflow_type())) + return result; + if(detail::check_underflow(val, &result, function, underflow_type())) + return result; + if(detail::check_denorm(val, &result, function, denorm_type())) + return result; + + return static_cast(val); +} + +template +inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol) +{ + if(max_iter >= policies::get_max_series_iterations()) + raise_evaluation_error( + function, + "Series evaluation exceeded %1% iterations, giving up now.", max_iter, pol); +} + +} //namespace policies + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +}} // namespaces boost/math + +#endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP + diff --git a/include/boost/math/policies/policy.hpp b/include/boost/math/policies/policy.hpp new file mode 100644 index 000000000..2558c99b6 --- /dev/null +++ b/include/boost/math/policies/policy.hpp @@ -0,0 +1,843 @@ +// Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_POLICY_HPP +#define BOOST_MATH_POLICY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Sadly we do need the .h versions of these to be sure of getting +// FLT_MANT_DIG etc. +#include +#include +#include +#include + +namespace boost{ namespace math{ + +namespace tools{ + +template +int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)); + +} + +namespace policies{ + +// +// Define macros for our default policies, if they're not defined already: +// +#ifndef BOOST_MATH_DOMAIN_ERROR_POLICY +#define BOOST_MATH_DOMAIN_ERROR_POLICY throw_on_error +#endif +#ifndef BOOST_MATH_POLE_ERROR_POLICY +#define BOOST_MATH_POLE_ERROR_POLICY throw_on_error +#endif +#ifndef BOOST_MATH_OVERFLOW_ERROR_POLICY +#define BOOST_MATH_OVERFLOW_ERROR_POLICY throw_on_error +#endif +#ifndef BOOST_MATH_EVALUATION_ERROR_POLICY +#define BOOST_MATH_EVALUATION_ERROR_POLICY throw_on_error +#endif +#ifndef BOOST_MATH_UNDERFLOW_ERROR_POLICY +#define BOOST_MATH_UNDERFLOW_ERROR_POLICY ignore_error +#endif +#ifndef BOOST_MATH_DENORM_ERROR_POLICY +#define BOOST_MATH_DENORM_ERROR_POLICY ignore_error +#endif +#ifndef BOOST_MATH_DIGITS10_POLICY +#define BOOST_MATH_DIGITS10_POLICY 0 +#endif +#ifndef BOOST_MATH_PROMOTE_FLOAT_POLICY +#define BOOST_MATH_PROMOTE_FLOAT_POLICY true +#endif +#ifndef BOOST_MATH_PROMOTE_DOUBLE_POLICY +#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#define BOOST_MATH_PROMOTE_DOUBLE_POLICY false +#else +#define BOOST_MATH_PROMOTE_DOUBLE_POLICY true +#endif +#endif +#ifndef BOOST_MATH_DISCRETE_QUANTILE_POLICY +#define BOOST_MATH_DISCRETE_QUANTILE_POLICY integer_round_outwards +#endif +#ifndef BOOST_MATH_ASSERT_UNDEFINED_POLICY +#define BOOST_MATH_ASSERT_UNDEFINED_POLICY true +#endif +#ifndef BOOST_MATH_MAX_SERIES_ITERATION_POLICY +#define BOOST_MATH_MAX_SERIES_ITERATION_POLICY 1000000 +#endif +#ifndef BOOST_MATH_MAX_ROOT_ITERATION_POLICY +#define BOOST_MATH_MAX_ROOT_ITERATION_POLICY 200 +#endif + +#if !defined(__BORLANDC__) +#define BOOST_MATH_META_INT(type, name, Default)\ + template struct name : public boost::mpl::int_{};\ + namespace detail{\ + template \ + char test_is_valid_arg(const name*);\ + char test_is_default_arg(const name*);\ + template struct is_##name##_imp\ + {\ + template static char test(const name*);\ + static double test(...);\ + BOOST_STATIC_CONSTANT(bool, value = sizeof(test(static_cast(0))) == 1);\ + };\ + }\ + template struct is_##name : public boost::mpl::bool_::value>{}; + +#define BOOST_MATH_META_BOOL(name, Default)\ + template struct name : public boost::mpl::bool_{};\ + namespace detail{\ + template \ + char test_is_valid_arg(const name*);\ + char test_is_default_arg(const name*);\ + template struct is_##name##_imp\ + {\ + template static char test(const name*);\ + static double test(...);\ + BOOST_STATIC_CONSTANT(bool, value = sizeof(test(static_cast(0))) == 1);\ + };\ + }\ + template struct is_##name : public boost::mpl::bool_::value>{}; +#else +#define BOOST_MATH_META_INT(Type, name, Default)\ + template struct name : public boost::mpl::int_{};\ + namespace detail{\ + template \ + char test_is_valid_arg(const name*);\ + char test_is_default_arg(const name*);\ + template struct is_##name##_tester\ + {\ + template static char test(const name&);\ + static double test(...);\ + };\ + template struct is_##name##_imp\ + {\ + static T inst;\ + BOOST_STATIC_CONSTANT(bool, value = sizeof(detail::is_##name##_tester::test(inst)) == 1);\ + };\ + }\ + template struct is_##name : public boost::mpl::bool_::value>\ + {\ + template struct apply{ typedef is_##name type; };\ + }; + +#define BOOST_MATH_META_BOOL(name, Default)\ + template struct name : public boost::mpl::bool_{};\ + namespace detail{\ + template \ + char test_is_valid_arg(const name*);\ + char test_is_default_arg(const name*);\ + template struct is_##name##_tester\ + {\ + template static char test(const name&);\ + static double test(...);\ + };\ + template struct is_##name##_imp\ + {\ + static T inst;\ + BOOST_STATIC_CONSTANT(bool, value = sizeof(detail::is_##name##_tester::test(inst)) == 1);\ + };\ + }\ + template struct is_##name : public boost::mpl::bool_::value>\ + {\ + template struct apply{ typedef is_##name type; };\ + }; +#endif +// +// Begin by defining policy types for error handling: +// +enum error_policy_type +{ + throw_on_error = 0, + errno_on_error = 1, + ignore_error = 2, + user_error = 3 +}; + +BOOST_MATH_META_INT(error_policy_type, domain_error, BOOST_MATH_DOMAIN_ERROR_POLICY) +BOOST_MATH_META_INT(error_policy_type, pole_error, BOOST_MATH_POLE_ERROR_POLICY) +BOOST_MATH_META_INT(error_policy_type, overflow_error, BOOST_MATH_OVERFLOW_ERROR_POLICY) +BOOST_MATH_META_INT(error_policy_type, underflow_error, BOOST_MATH_UNDERFLOW_ERROR_POLICY) +BOOST_MATH_META_INT(error_policy_type, denorm_error, BOOST_MATH_DENORM_ERROR_POLICY) +BOOST_MATH_META_INT(error_policy_type, evaluation_error, BOOST_MATH_EVALUATION_ERROR_POLICY) + +// +// Policy types for internal promotion: +// +BOOST_MATH_META_BOOL(promote_float, BOOST_MATH_PROMOTE_FLOAT_POLICY) +BOOST_MATH_META_BOOL(promote_double, BOOST_MATH_PROMOTE_DOUBLE_POLICY) +BOOST_MATH_META_BOOL(assert_undefined, BOOST_MATH_ASSERT_UNDEFINED_POLICY) +// +// Policy types for discrete quantiles: +// +enum discrete_quantile_policy_type +{ + real, + integer_round_outwards, + integer_round_inwards, + integer_round_down, + integer_round_up, + integer_round_nearest +}; + +BOOST_MATH_META_INT(discrete_quantile_policy_type, discrete_quantile, BOOST_MATH_DISCRETE_QUANTILE_POLICY) +// +// Precision: +// +BOOST_MATH_META_INT(int, digits10, BOOST_MATH_DIGITS10_POLICY) +BOOST_MATH_META_INT(int, digits2, 0) +// +// Iterations: +// +BOOST_MATH_META_INT(unsigned long, max_series_iterations, BOOST_MATH_MAX_SERIES_ITERATION_POLICY) +BOOST_MATH_META_INT(unsigned long, max_root_iterations, BOOST_MATH_MAX_ROOT_ITERATION_POLICY) +// +// Define the names for each possible policy: +// +#define BOOST_MATH_PARAMETER(name)\ + BOOST_PARAMETER_TEMPLATE_KEYWORD(name##_name)\ + BOOST_PARAMETER_NAME(name##_name) + +struct default_policy{}; + +namespace detail{ +// +// Trait to work out bits precision from digits10 and digits2: +// +template +struct precision +{ + // + // Now work out the precision: + // + typedef typename mpl::if_c< + (Digits10::value == 0), + digits2<0>, + digits2<((Digits10::value + 1) * 1000L) / 301L> + >::type digits2_type; +public: +#ifdef __BORLANDC__ + typedef typename mpl::if_c< + (Digits2::value > ::boost::math::policies::detail::precision::digits2_type::value), + Digits2, digits2_type>::type type; +#else + typedef typename mpl::if_c< + (Digits2::value > digits2_type::value), + Digits2, digits2_type>::type type; +#endif +}; + +template +struct select_result +{ + typedef A type; +}; +template +struct select_result +{ + typedef typename mpl::deref::type type; +}; + +template +struct find_arg +{ +private: + typedef typename mpl::find_if::type iter; + typedef typename mpl::end::type end_type; +public: + typedef typename select_result< + DefaultType, iter, + ::boost::is_same::value>::type type; +}; + +double test_is_valid_arg(...); +double test_is_default_arg(...); +char test_is_valid_arg(const default_policy*); +char test_is_default_arg(const default_policy*); + +template +struct is_valid_policy_imp +{ + BOOST_STATIC_CONSTANT(bool, value = sizeof(test_is_valid_arg(static_cast(0))) == 1); +}; + +template +struct is_default_policy_imp +{ + BOOST_STATIC_CONSTANT(bool, value = sizeof(test_is_default_arg(static_cast(0))) == 1); +}; + +template struct is_valid_policy +: public mpl::bool_< + ::boost::math::policies::detail::is_valid_policy_imp::value> +{}; + +template struct is_default_policy +: public mpl::bool_< + ::boost::math::policies::detail::is_default_policy_imp::value> +{ + template + struct apply + { + typedef is_default_policy type; + }; +}; + +template +struct append_N +{ + typedef typename mpl::push_back::type new_seq; + typedef typename append_N::type type; +}; + +template +struct append_N +{ + typedef Seq type; +}; + +// +// Traits class to work out what template parameters our default +// policy<> class will have when modified for forwarding: +// +template +struct default_args +{ + typedef promote_float arg1; + typedef promote_double arg2; +}; + +template <> +struct default_args +{ + typedef default_policy arg1; + typedef default_policy arg2; +}; + +template <> +struct default_args +{ + typedef promote_float arg1; + typedef default_policy arg2; +}; + +template <> +struct default_args +{ + typedef promote_double arg1; + typedef default_policy arg2; +}; + +typedef default_args::arg1 forwarding_arg1; +typedef default_args::arg2 forwarding_arg2; + +} // detail +// +// Now define the policy type with enough arguments to handle all +// the policies: +// +template +struct policy +{ +private: + // + // Validate all our arguments: + // + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy::value); + // + // Typelist of the arguments: + // + typedef mpl::list arg_list; + +public: + typedef typename detail::find_arg, domain_error<> >::type domain_error_type; + typedef typename detail::find_arg, pole_error<> >::type pole_error_type; + typedef typename detail::find_arg, overflow_error<> >::type overflow_error_type; + typedef typename detail::find_arg, underflow_error<> >::type underflow_error_type; + typedef typename detail::find_arg, denorm_error<> >::type denorm_error_type; + typedef typename detail::find_arg, evaluation_error<> >::type evaluation_error_type; +private: + // + // Now work out the precision: + // + typedef typename detail::find_arg, digits10<> >::type digits10_type; + typedef typename detail::find_arg, digits2<> >::type bits_precision_type; +public: + typedef typename detail::precision::type precision_type; + // + // Internal promotion: + // + typedef typename detail::find_arg, promote_float<> >::type promote_float_type; + typedef typename detail::find_arg, promote_double<> >::type promote_double_type; + // + // Discrete quantiles: + // + typedef typename detail::find_arg, discrete_quantile<> >::type discrete_quantile_type; + // + // Mathematically undefined properties: + // + typedef typename detail::find_arg, discrete_quantile<> >::type assert_undefined_type; + // + // Max iterations: + // + typedef typename detail::find_arg, max_series_iterations<> >::type max_series_iterations_type; + typedef typename detail::find_arg, max_root_iterations<> >::type max_root_iterations_type; +}; +// +// These full specializations are defined to reduce the amount of +// template instantiations that have to take place when using the default +// policies, they have quite a large impact on compile times: +// +template <> +struct policy +{ +public: + typedef domain_error<> domain_error_type; + typedef pole_error<> pole_error_type; + typedef overflow_error<> overflow_error_type; + typedef underflow_error<> underflow_error_type; + typedef denorm_error<> denorm_error_type; + typedef evaluation_error<> evaluation_error_type; +#if BOOST_MATH_DIGITS10_POLICY == 0 + typedef digits2<> precision_type; +#else + typedef detail::precision, digits2<> >::type precision_type; +#endif + typedef promote_float<> promote_float_type; + typedef promote_double<> promote_double_type; + typedef discrete_quantile<> discrete_quantile_type; + typedef assert_undefined<> assert_undefined_type; + typedef max_series_iterations<> max_series_iterations_type; + typedef max_root_iterations<> max_root_iterations_type; +}; + +template <> +struct policy +{ +public: + typedef domain_error<> domain_error_type; + typedef pole_error<> pole_error_type; + typedef overflow_error<> overflow_error_type; + typedef underflow_error<> underflow_error_type; + typedef denorm_error<> denorm_error_type; + typedef evaluation_error<> evaluation_error_type; +#if BOOST_MATH_DIGITS10_POLICY == 0 + typedef digits2<> precision_type; +#else + typedef detail::precision, digits2<> >::type precision_type; +#endif + typedef promote_float promote_float_type; + typedef promote_double promote_double_type; + typedef discrete_quantile<> discrete_quantile_type; + typedef assert_undefined<> assert_undefined_type; + typedef max_series_iterations<> max_series_iterations_type; + typedef max_root_iterations<> max_root_iterations_type; +}; + +template +struct normalise +{ +private: + typedef mpl::list arg_list; + typedef typename detail::find_arg, typename Policy::domain_error_type >::type domain_error_type; + typedef typename detail::find_arg, typename Policy::pole_error_type >::type pole_error_type; + typedef typename detail::find_arg, typename Policy::overflow_error_type >::type overflow_error_type; + typedef typename detail::find_arg, typename Policy::underflow_error_type >::type underflow_error_type; + typedef typename detail::find_arg, typename Policy::denorm_error_type >::type denorm_error_type; + typedef typename detail::find_arg, typename Policy::evaluation_error_type >::type evaluation_error_type; + // + // Now work out the precision: + // + typedef typename detail::find_arg, digits10<> >::type digits10_type; + typedef typename detail::find_arg, typename Policy::precision_type >::type bits_precision_type; + typedef typename detail::precision::type precision_type; + // + // Internal promotion: + // + typedef typename detail::find_arg, typename Policy::promote_float_type >::type promote_float_type; + typedef typename detail::find_arg, typename Policy::promote_double_type >::type promote_double_type; + // + // Discrete quantiles: + // + typedef typename detail::find_arg, typename Policy::discrete_quantile_type >::type discrete_quantile_type; + // + // Mathematically undefined properties: + // + typedef typename detail::find_arg, discrete_quantile<> >::type assert_undefined_type; + // + // Max iterations: + // + typedef typename detail::find_arg, max_series_iterations<> >::type max_series_iterations_type; + typedef typename detail::find_arg, max_root_iterations<> >::type max_root_iterations_type; + // + // Define a typelist of the policies: + // + typedef mpl::vector< + domain_error_type, + pole_error_type, + overflow_error_type, + underflow_error_type, + denorm_error_type, + evaluation_error_type, + precision_type, + promote_float_type, + promote_double_type, + discrete_quantile_type, + assert_undefined_type, + max_series_iterations_type, + max_root_iterations_type> result_list; + // + // Remove all the policies that are the same as the default: + // + typedef typename mpl::remove_if >::type reduced_list; + // + // Pad out the list with defaults: + // + typedef typename detail::append_N::value)>::type result_type; +public: + typedef policy< + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type, + typename mpl::at >::type > type; +}; +// +// Full specialisation to speed up compilation of the common case: +// +template <> +struct normalise, + promote_float, + promote_double, + discrete_quantile<>, + assert_undefined<>, + default_policy, + default_policy, + default_policy, + default_policy, + default_policy, + default_policy, + default_policy> +{ + typedef policy type; +}; + +inline policy<> make_policy() +{ return policy<>(); } + +template +inline typename normalise, A1>::type make_policy(const A1&) +{ + typedef typename normalise, A1>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2>::type make_policy(const A1&, const A2&) +{ + typedef typename normalise, A1, A2>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3>::type make_policy(const A1&, const A2&, const A3&) +{ + typedef typename normalise, A1, A2, A3>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4>::type make_policy(const A1&, const A2&, const A3&, const A4&) +{ + typedef typename normalise, A1, A2, A3, A4>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&) +{ + typedef typename normalise, A1, A2, A3, A4, A5>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5, A6>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&) +{ + typedef typename normalise, A1, A2, A3, A4, A5, A6>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5, A6, A7>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&) +{ + typedef typename normalise, A1, A2, A3, A4, A5, A6, A7>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5, A6, A7, A8>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&) +{ + typedef typename normalise, A1, A2, A3, A4, A5, A6, A7, A8>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5, A6, A7, A8, A9>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&, const A9&) +{ + typedef typename normalise, A1, A2, A3, A4, A5, A6, A7, A8, A9>::type result_type; + return result_type(); +} + +template +inline typename normalise, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&, const A9&, const A10&) +{ + typedef typename normalise, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::type result_type; + return result_type(); +} + +// +// Traits class to handle internal promotion: +// +template +struct evaluation +{ + typedef Real type; +}; + +template +struct evaluation +{ + typedef typename mpl::if_::type type; +}; + +template +struct evaluation +{ + typedef typename mpl::if_::type type; +}; + +#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + +template +struct basic_digits : public mpl::int_<0>{ }; +template <> +struct basic_digits : public mpl::int_{ }; +template <> +struct basic_digits : public mpl::int_{ }; +template <> +struct basic_digits : public mpl::int_{ }; + +template +struct precision +{ + typedef typename Policy::precision_type precision_type; + typedef basic_digits digits_t; + typedef typename mpl::if_< + mpl::equal_to >, + // Possibly unknown precision: + precision_type, + typename mpl::if_< + mpl::or_, mpl::less_equal > >, + // Default case, full precision for RealType: + digits2< ::std::numeric_limits::digits>, + // User customised precision: + precision_type + >::type + >::type type; +}; + +template +struct precision +{ + typedef digits2 type; +}; +template +struct precision +{ + typedef digits2 type; +}; +template +struct precision +{ + typedef digits2 type; +}; + +#else + +template +struct precision +{ +#ifndef __BORLANDC__ + typedef typename Policy::precision_type precision_type; + typedef typename mpl::if_c< + ((::std::numeric_limits::is_specialized == 0) || (::std::numeric_limits::digits == 0)), + // Possibly unknown precision: + precision_type, + typename mpl::if_c< + ((::std::numeric_limits::digits <= precision_type::value) + || (Policy::precision_type::value <= 0)), + // Default case, full precision for RealType: + digits2< ::std::numeric_limits::digits>, + // User customised precision: + precision_type + >::type + >::type type; +#else + typedef typename Policy::precision_type precision_type; + typedef mpl::int_< ::std::numeric_limits::digits> digits_t; + typedef mpl::bool_< ::std::numeric_limits::is_specialized> spec_t; + typedef typename mpl::if_< + mpl::or_, mpl::equal_to > >, + // Possibly unknown precision: + precision_type, + typename mpl::if_< + mpl::or_, mpl::less_equal > >, + // Default case, full precision for RealType: + digits2< ::std::numeric_limits::digits>, + // User customised precision: + precision_type + >::type + >::type type; +#endif +}; + +#endif + +namespace detail{ + +template +inline int digits_imp(mpl::true_ const&) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + typedef typename boost::math::policies::precision::type p_t; + return p_t::value; +} + +template +inline int digits_imp(mpl::false_ const&) +{ + return tools::digits(); +} + +} // namespace detail + +template +inline int digits() +{ + typedef mpl::bool_< std::numeric_limits::is_specialized > tag_type; + return detail::digits_imp(tag_type()); +} + +template +inline unsigned long get_max_series_iterations() +{ + typedef typename Policy::max_series_iterations_type iter_type; + return iter_type::value; +} + +template +inline unsigned long get_max_root_iterations() +{ + typedef typename Policy::max_root_iterations_type iter_type; + return iter_type::value; +} + +namespace detail{ + +template +char test_is_policy(const policy*); +double test_is_policy(...); + +template +struct is_policy_imp +{ + BOOST_STATIC_CONSTANT(bool, value = (sizeof(test_is_policy(static_cast(0))) == 1)); +}; + +} + +template +struct is_policy : public mpl::bool_< ::boost::math::policies::detail::is_policy_imp

::value> {}; + +}}} // namespaces + +#endif // BOOST_MATH_POLICY_HPP + + diff --git a/include/boost/math/special_functions.hpp b/include/boost/math/special_functions.hpp new file mode 100644 index 000000000..0575b7560 --- /dev/null +++ b/include/boost/math/special_functions.hpp @@ -0,0 +1,51 @@ +// Copyright John Maddock 2006, 2007. +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This file includes *all* the special functions. +// this may be useful if many are used +// - to avoid including each function individually. + +#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_HPP +#define BOOST_MATH_SPECIAL_FUNCTIONS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_MATH_SPECIAL_FUNCTIONS_HPP diff --git a/include/boost/math/special_functions/acosh.hpp b/include/boost/math/special_functions/acosh.hpp index 3175ee1eb..5fa16a807 100644 --- a/include/boost/math/special_functions/acosh.hpp +++ b/include/boost/math/special_functions/acosh.hpp @@ -12,13 +12,10 @@ #include -#include -#include -#include - - #include - +#include +#include +#include // This is the inverse of the hyperbolic cosine function. @@ -26,6 +23,8 @@ namespace boost { namespace math { + namespace detail + { #if defined(__GNUC__) && (__GNUC__ < 3) // gcc 2.x ignores function scope using declarations, // put them in the scope of the enclosing namespace instead: @@ -37,39 +36,25 @@ namespace boost using ::std::numeric_limits; #endif -#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - // This is the main fare - - template - inline T acosh(const T x) + template + inline T acosh_imp(const T x, const Policy& pol) { using ::std::abs; using ::std::sqrt; using ::std::log; - using ::std::numeric_limits; - - T const one = static_cast(1); T const two = static_cast(2); - static T const taylor_2_bound = sqrt(numeric_limits::epsilon()); + static T const taylor_2_bound = sqrt(tools::epsilon()); static T const taylor_n_bound = sqrt(taylor_2_bound); static T const upper_taylor_2_bound = one/taylor_2_bound; - if (x < one) + if(x < one) { - if (numeric_limits::has_quiet_NaN) - { - return(numeric_limits::quiet_NaN()); - } - else - { - ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!"); - ::std::domain_error bad_argument(error_reporting); - - throw(bad_argument); - } + return policies::raise_domain_error( + "boost::math::acosh<%1%>(%1%)", + "acosh requires x >= 1, but got x = %1%.", x, pol); } else if (x >= taylor_n_bound) { @@ -101,98 +86,27 @@ namespace boost return(sqrt(static_cast(2))*result); } } -#else - // These are implementation details (for main fare see below) - - namespace detail + } + + template + inline typename tools::promote_args::type acosh(const T x, const Policy& pol) { - template < - typename T, - bool QuietNanSupported - > - struct acosh_helper2_t - { - static T get_NaN() - { - return(::std::numeric_limits::quiet_NaN()); - } - }; // boost::detail::acosh_helper2_t - - - template - struct acosh_helper2_t - { - static T get_NaN() - { - ::std::string error_reporting("Argument to acosh is greater than or equal to +1!"); - ::std::domain_error bad_argument(error_reporting); - - throw(bad_argument); - } - }; // boost::detail::acosh_helper2_t - - } // boost::detail - - - // This is the main fare - - template - inline T acosh(const T x) - { - using ::std::abs; - using ::std::sqrt; - using ::std::log; - - using ::std::numeric_limits; - - typedef detail::acosh_helper2_t::has_quiet_NaN> helper2_type; - - - T const one = static_cast(1); - T const two = static_cast(2); - - static T const taylor_2_bound = sqrt(numeric_limits::epsilon()); - static T const taylor_n_bound = sqrt(taylor_2_bound); - static T const upper_taylor_2_bound = one/taylor_2_bound; - - if (x < one) - { - return(helper2_type::get_NaN()); - } - else if (x >= taylor_n_bound) - { - if (x > upper_taylor_2_bound) - { - // approximation by laurent series in 1/x at 0+ order from -1 to 0 - return( log( x*two) ); - } - else - { - return( log( x + sqrt(x*x-one) ) ); - } - } - else - { - T y = sqrt(x-one); - - // approximation by taylor series in y at 0 up to order 2 - T result = y; - - if (y >= taylor_2_bound) - { - T y3 = y*y*y; - - // approximation by taylor series in y at 0 up to order 4 - result -= y3/static_cast(12); - } - - return(sqrt(static_cast(2))*result); - } + typedef typename tools::promote_args::type result_type; + return detail::acosh_imp( + static_cast(x), pol); } -#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */ + template + inline typename tools::promote_args::type acosh(const T x) + { + typedef typename tools::promote_args::type result_type; + return detail::acosh_imp( + static_cast(x), policies::policy<>()); + } + } } #endif /* BOOST_ACOSH_HPP */ + diff --git a/include/boost/math/special_functions/asinh.hpp b/include/boost/math/special_functions/asinh.hpp index 24b727fea..502e514b0 100644 --- a/include/boost/math/special_functions/asinh.hpp +++ b/include/boost/math/special_functions/asinh.hpp @@ -12,13 +12,9 @@ #include -#include -#include -#include - - #include - +#include +#include // This is the inverse of the hyperbolic sine function. @@ -26,6 +22,7 @@ namespace boost { namespace math { + namespace detail{ #if defined(__GNUC__) && (__GNUC__ < 3) // gcc 2.x ignores function scope using declarations, // put them in the scope of the enclosing namespace instead: @@ -38,19 +35,16 @@ namespace boost #endif template - inline T asinh(const T x) + inline T asinh_imp(const T x) { using ::std::abs; using ::std::sqrt; using ::std::log; - using ::std::numeric_limits; - - T const one = static_cast(1); T const two = static_cast(2); - static T const taylor_2_bound = sqrt(numeric_limits::epsilon()); + static T const taylor_2_bound = sqrt(tools::epsilon()); static T const taylor_n_bound = sqrt(taylor_2_bound); static T const upper_taylor_2_bound = one/taylor_2_bound; static T const upper_taylor_n_bound = one/taylor_n_bound; @@ -95,6 +89,23 @@ namespace boost return(result); } } + } + + template + inline typename tools::promote_args::type asinh(const T x) + { + typedef typename tools::promote_args::type result_type; + return detail::asinh_imp( + static_cast(x)); + } + template + inline typename tools::promote_args::type asinh(const T x, const Policy&) + { + typedef typename tools::promote_args::type result_type; + return detail::asinh_imp( + static_cast(x)); + } + } } diff --git a/include/boost/math/special_functions/atanh.hpp b/include/boost/math/special_functions/atanh.hpp index 35011763f..35325a3d7 100644 --- a/include/boost/math/special_functions/atanh.hpp +++ b/include/boost/math/special_functions/atanh.hpp @@ -12,13 +12,10 @@ #include -#include -#include -#include - - #include - +#include +#include +#include // This is the inverse of the hyperbolic tangent function. @@ -26,6 +23,8 @@ namespace boost { namespace math { + namespace detail + { #if defined(__GNUC__) && (__GNUC__ < 3) // gcc 2.x ignores function scope using declarations, // put them in the scope of the enclosing namespace instead: @@ -37,11 +36,10 @@ namespace boost using ::std::numeric_limits; #endif -#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) // This is the main fare - template - inline T atanh(const T x) + template + inline T atanh_imp(const T x, const Policy& pol) { using ::std::abs; using ::std::sqrt; @@ -52,64 +50,32 @@ namespace boost T const one = static_cast(1); T const two = static_cast(2); - static T const taylor_2_bound = sqrt(numeric_limits::epsilon()); + static T const taylor_2_bound = sqrt(tools::epsilon()); static T const taylor_n_bound = sqrt(taylor_2_bound); + + static const char* function = "boost::math::atanh<%1%>(%1%)"; if (x < -one) { - if (numeric_limits::has_quiet_NaN) - { - return(numeric_limits::quiet_NaN()); - } - else - { - ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!"); - ::std::domain_error bad_argument(error_reporting); - - throw(bad_argument); - } + return policies::raise_domain_error( + function, + "atanh requires x >= -1, but got x = %1%.", x, pol); } - else if (x < -one+numeric_limits::epsilon()) + else if (x < -one + tools::epsilon()) { - if (numeric_limits::has_infinity) - { - return(-numeric_limits::infinity()); - } - else - { - ::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!"); - ::std::out_of_range bad_argument(error_reporting); - - throw(bad_argument); - } + // -Infinity: + return -policies::raise_overflow_error(function, 0, pol); } - else if (x > +one-numeric_limits::epsilon()) + else if (x > one - tools::epsilon()) { - if (numeric_limits::has_infinity) - { - return(+numeric_limits::infinity()); - } - else - { - ::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!"); - ::std::out_of_range bad_argument(error_reporting); - - throw(bad_argument); - } + // Infinity: + return -policies::raise_overflow_error(function, 0, pol); } else if (x > +one) { - if (numeric_limits::has_quiet_NaN) - { - return(numeric_limits::quiet_NaN()); - } - else - { - ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!"); - ::std::domain_error bad_argument(error_reporting); - - throw(bad_argument); - } + return policies::raise_domain_error( + function, + "atanh requires x <= 1, but got x = %1%.", x, pol); } else if (abs(x) >= taylor_n_bound) { @@ -131,137 +97,26 @@ namespace boost return(result); } } -#else - // These are implementation details (for main fare see below) - - namespace detail + } + + template + inline typename tools::promote_args::type atanh(const T x, const Policy& pol) { - template < - typename T, - bool InfinitySupported - > - struct atanh_helper1_t - { - static T get_pos_infinity() - { - return(+::std::numeric_limits::infinity()); - } - - static T get_neg_infinity() - { - return(-::std::numeric_limits::infinity()); - } - }; // boost::math::detail::atanh_helper1_t - - - template - struct atanh_helper1_t - { - static T get_pos_infinity() - { - ::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!"); - ::std::out_of_range bad_argument(error_reporting); - - throw(bad_argument); - } - - static T get_neg_infinity() - { - ::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!"); - ::std::out_of_range bad_argument(error_reporting); - - throw(bad_argument); - } - }; // boost::math::detail::atanh_helper1_t - - - template < - typename T, - bool QuietNanSupported - > - struct atanh_helper2_t - { - static T get_NaN() - { - return(::std::numeric_limits::quiet_NaN()); - } - }; // boost::detail::atanh_helper2_t - - - template - struct atanh_helper2_t - { - static T get_NaN() - { - ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!"); - ::std::domain_error bad_argument(error_reporting); - - throw(bad_argument); - } - }; // boost::detail::atanh_helper2_t - } // boost::detail - - - // This is the main fare - + typedef typename tools::promote_args::type result_type; + return detail::atanh_imp( + static_cast(x), pol); + } template - inline T atanh(const T x) + inline typename tools::promote_args::type atanh(const T x) { - using ::std::abs; - using ::std::sqrt; - using ::std::log; - - using ::std::numeric_limits; - - typedef detail::atanh_helper1_t::has_infinity> helper1_type; - typedef detail::atanh_helper2_t::has_quiet_NaN> helper2_type; - - - T const one = static_cast(1); - T const two = static_cast(2); - - static T const taylor_2_bound = sqrt(numeric_limits::epsilon()); - static T const taylor_n_bound = sqrt(taylor_2_bound); - - if (x < -one) - { - return(helper2_type::get_NaN()); - } - else if (x < -one+numeric_limits::epsilon()) - { - return(helper1_type::get_neg_infinity()); - } - else if (x > +one-numeric_limits::epsilon()) - { - return(helper1_type::get_pos_infinity()); - } - else if (x > +one) - { - return(helper2_type::get_NaN()); - } - else if (abs(x) >= taylor_n_bound) - { - return(log( (one + x) / (one - x) ) / two); - } - else - { - // approximation by taylor series in x at 0 up to order 2 - T result = x; - - if (abs(x) >= taylor_2_bound) - { - T x3 = x*x*x; - - // approximation by taylor series in x at 0 up to order 4 - result += x3/static_cast(3); - } - - return(result); - } + typedef typename tools::promote_args::type result_type; + return detail::atanh_imp( + static_cast(x), policies::policy<>()); } -#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */ + } } #endif /* BOOST_ATANH_HPP */ + diff --git a/include/boost/math/special_functions/bessel.hpp b/include/boost/math/special_functions/bessel.hpp new file mode 100644 index 000000000..98b32b33c --- /dev/null +++ b/include/boost/math/special_functions/bessel.hpp @@ -0,0 +1,484 @@ +// Copyright (c) 2007 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This header just defines the function entry points, and adds dispatch +// to the right implementation method. Most of the implementation details +// are in separate headers and copyright Xiaogang Zhang. +// +#ifndef BOOST_MATH_BESSEL_HPP +#define BOOST_MATH_BESSEL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ + +namespace detail{ + +template +struct bessel_j_small_z_series_term +{ + typedef T result_type; + + bessel_j_small_z_series_term(T v_, T x) + : N(0), v(v_) + { + BOOST_MATH_STD_USING + mult = x / 2; + term = pow(mult, v) / boost::math::tgamma(v+1, Policy()); + mult *= -mult; + } + T operator()() + { + T r = term; + ++N; + term *= mult / (N * (N + v)); + return r; + } +private: + unsigned N; + T v; + T mult; + T term; +}; + +template +struct sph_bessel_j_small_z_series_term +{ + typedef T result_type; + + sph_bessel_j_small_z_series_term(unsigned v_, T x) + : N(0), v(v_) + { + BOOST_MATH_STD_USING + mult = x / 2; + term = pow(mult, T(v)) / boost::math::tgamma(v+1+T(0.5f), Policy()); + mult *= -mult; + } + T operator()() + { + T r = term; + ++N; + term *= mult / (N * T(N + v + 0.5f)); + return r; + } +private: + unsigned N; + unsigned v; + T mult; + T term; +}; + +template +inline T bessel_j_small_z_series(T v, T x, const Policy& pol) +{ + bessel_j_small_z_series_term s(v, x); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T zero = 0; + T result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter, zero); +#else + T result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter); +#endif + policies::check_series_iterations("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol); + return result; +} + +template +inline T sph_bessel_j_small_z_series(unsigned v, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + sph_bessel_j_small_z_series_term s(v, x); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T zero = 0; + T result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter, zero); +#else + T result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter); +#endif + policies::check_series_iterations("boost::math::sph_bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol); + return result * sqrt(constants::pi() / 4); +} + +template +T cyl_bessel_j_imp(T v, T x, const bessel_no_int_tag& t, const Policy& pol) +{ + BOOST_MATH_STD_USING + static const char* function = "boost::math::bessel_j<%1%>(%1%,%1%)"; + if(x < 0) + { + // better have integer v: + if(floor(v) == v) + { + T r = cyl_bessel_j_imp(v, -x, t, pol); + if(tools::real_cast(v) & 1) + r = -r; + return r; + } + else + return policies::raise_domain_error( + function, + "Got x = %1%, but we need x >= 0", x, pol); + } + if(x == 0) + return (v == 0) ? 1 : (v > 0) ? 0 : + policies::raise_domain_error( + function, + "Got v = %1%, but require v >= 0 or a negative integer: the result would be complex.", v, pol); + + + if((v >= 0) && ((x < 1) || (v > x * x / 4))) + { + return bessel_j_small_z_series(v, x, pol); + } + + T j, y; + bessel_jy(v, x, &j, &y, need_j, pol); + return j; +} + +template +inline T cyl_bessel_j_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names. + typedef typename bessel_asymptotic_tag::type tag_type; + if((fabs(v) < 200) && (floor(v) == v)) + { + if(fabs(x) > asymptotic_bessel_j_limit(v, tag_type())) + return asymptotic_bessel_j_large_x_2(v, x); + else + return bessel_jn(tools::real_cast(v), x, pol); + } + return cyl_bessel_j_imp(v, x, bessel_no_int_tag(), pol); +} + +template +inline T cyl_bessel_j_imp(int v, T x, const bessel_int_tag&, const Policy& pol) +{ + BOOST_MATH_STD_USING + typedef typename bessel_asymptotic_tag::type tag_type; + if(fabs(x) > asymptotic_bessel_j_limit(abs(v), tag_type())) + { + T r = asymptotic_bessel_j_large_x_2(static_cast(abs(v)), x); + if((v < 0) && (v & 1)) + r = -r; + return r; + } + else + return bessel_jn(v, x, pol); +} + +template +inline T sph_bessel_j_imp(unsigned n, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + if(x < 0) + return policies::raise_domain_error( + "boost::math::sph_bessel_j<%1%>(%1%,%1%)", + "Got x = %1%, but function requires x > 0.", x, pol); + // + // Special case, n == 0 resolves down to the sinus cardinal of x: + // + if(n == 0) + return boost::math::sinc_pi(x, pol); + // + // When x is small we may end up with 0/0, use series evaluation + // instead, especially as it converges rapidly: + // + if(x < 1) + return sph_bessel_j_small_z_series(n, x, pol); + // + // Default case is just a naive evaluation of the definition: + // + return sqrt(constants::pi() / (2 * x)) + * cyl_bessel_j_imp(T(n)+T(0.5f), x, bessel_no_int_tag(), pol); +} + +template +T cyl_bessel_i_imp(T v, T x, const Policy& pol) +{ + // + // This handles all the bessel I functions, note that we don't optimise + // for integer v, other than the v = 0 or 1 special cases, as Millers + // algorithm is at least as inefficient as the general case (the general + // case has better error handling too). + // + BOOST_MATH_STD_USING + if(x < 0) + { + // better have integer v: + if(floor(v) == v) + { + T r = cyl_bessel_i_imp(v, -x, pol); + if(tools::real_cast(v) & 1) + r = -r; + return r; + } + else + return policies::raise_domain_error( + "boost::math::cyl_bessel_i<%1%>(%1%,%1%)", + "Got x = %1%, but we need x >= 0", x, pol); + } + if(x == 0) + { + return (v == 0) ? 1 : 0; + } + if(v == 0.5f) + { + // common special case, note try and avoid overflow in exp(x): + T e = exp(x / 2); + return e * (e / sqrt(2 * x * constants::pi())); + } + if(policies::digits() <= 64) + { + if(v == 0) + { + return bessel_i0(x); + } + if(v == 1) + { + return bessel_i1(x); + } + } + T I, K; + bessel_ik(v, x, &I, &K, need_i, pol); + return I; +} + +template +inline T cyl_bessel_k_imp(T v, T x, const bessel_no_int_tag& /* t */, const Policy& pol) +{ + static const char* function = "boost::math::cyl_bessel_k<%1%>(%1%,%1%)"; + BOOST_MATH_STD_USING + if(x < 0) + { + return policies::raise_domain_error( + function, + "Got x = %1%, but we need x > 0", x, pol); + } + if(x == 0) + { + return (v == 0) ? policies::raise_overflow_error(function, 0, pol) + : policies::raise_domain_error( + function, + "Got x = %1%, but we need x > 0", x, pol); + } + T I, K; + bessel_ik(v, x, &I, &K, need_k, pol); + return K; +} + +template +inline T cyl_bessel_k_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol) +{ + BOOST_MATH_STD_USING + if((floor(v) == v)) + { + return bessel_kn(tools::real_cast(v), x, pol); + } + return cyl_bessel_k_imp(v, x, bessel_no_int_tag(), pol); +} + +template +inline T cyl_bessel_k_imp(int v, T x, const bessel_int_tag&, const Policy& pol) +{ + return bessel_kn(v, x, pol); +} + +template +inline T cyl_neumann_imp(T v, T x, const bessel_no_int_tag&, const Policy& pol) +{ + static const char* function = "boost::math::cyl_neumann<%1%>(%1%,%1%)"; + if(x <= 0) + { + return (v == 0) && (x == 0) ? + policies::raise_overflow_error(function, 0, pol) + : policies::raise_domain_error( + function, + "Got x = %1%, but result is complex for x <= 0", x, pol); + } + T j, y; + bessel_jy(v, x, &j, &y, need_y, pol); + // + // Post evaluation check for internal overflow during evaluation, + // can occur when x is small and v is large, in which case the result + // is -INF: + // + if(!(boost::math::isfinite)(y)) + return -policies::raise_overflow_error(function, 0, pol); + return y; +} + +template +inline T cyl_neumann_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol) +{ + BOOST_MATH_STD_USING + typedef typename bessel_asymptotic_tag::type tag_type; + if(floor(v) == v) + { + if((fabs(x) > asymptotic_bessel_y_limit(tag_type())) && (fabs(x) > 5 * abs(v))) + { + T r = asymptotic_bessel_y_large_x_2(static_cast(abs(v)), x); + if((v < 0) && (tools::real_cast(v) & 1)) + r = -r; + return r; + } + else + return bessel_yn(tools::real_cast(v), x, pol); + } + return cyl_neumann_imp(v, x, bessel_no_int_tag(), pol); +} + +template +inline T cyl_neumann_imp(int v, T x, const bessel_int_tag&, const Policy& pol) +{ + BOOST_MATH_STD_USING + typedef typename bessel_asymptotic_tag::type tag_type; + if((fabs(x) > asymptotic_bessel_y_limit(tag_type())) && (fabs(x) > 5 * abs(v))) + { + T r = asymptotic_bessel_y_large_x_2(static_cast(abs(v)), x); + if((v < 0) && (v & 1)) + r = -r; + return r; + } + else + return bessel_yn(tools::real_cast(v), x, pol); +} + +template +inline T sph_neumann_imp(unsigned v, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + static const char* function = "boost::math::sph_neumann<%1%>(%1%,%1%)"; + // + // Nothing much to do here but check for errors, and + // evaluate the function's definition directly: + // + if(x < 0) + return policies::raise_domain_error( + function, + "Got x = %1%, but function requires x > 0.", x, pol); + + if(x < 2 * tools::min_value()) + return -policies::raise_overflow_error(function, 0, pol); + + T result = cyl_neumann_imp(T(v)+0.5f, x, bessel_no_int_tag(), pol); + T tx = sqrt(constants::pi() / (2 * x)); + + if((tx > 1) && (tools::max_value() / tx < result)) + return -policies::raise_overflow_error(function, 0, pol); + + return result * tx; +} + +} // namespace detail + +template +inline typename detail::bessel_traits::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename detail::bessel_traits::optimisation_tag tag_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::cyl_bessel_j_imp(v, static_cast(x), tag_type(), pol), "boost::math::cyl_bessel_j<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type cyl_bessel_j(T1 v, T2 x) +{ + return cyl_bessel_j(v, x, policies::policy<>()); +} + +template +inline typename detail::bessel_traits::result_type sph_bessel(unsigned v, T x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::sph_bessel_j_imp(v, static_cast(x), pol), "boost::math::sph_bessel<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type sph_bessel(unsigned v, T x) +{ + return sph_bessel(v, x, policies::policy<>()); +} + +template +inline typename detail::bessel_traits::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::cyl_bessel_i_imp(v, static_cast(x), pol), "boost::math::cyl_bessel_i<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type cyl_bessel_i(T1 v, T2 x) +{ + return cyl_bessel_i(v, x, policies::policy<>()); +} + +template +inline typename detail::bessel_traits::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename detail::bessel_traits::optimisation_tag tag_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::cyl_bessel_k_imp(v, static_cast(x), tag_type(), pol), "boost::math::cyl_bessel_k<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type cyl_bessel_k(T1 v, T2 x) +{ + return cyl_bessel_k(v, x, policies::policy<>()); +} + +template +inline typename detail::bessel_traits::result_type cyl_neumann(T1 v, T2 x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename detail::bessel_traits::optimisation_tag tag_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::cyl_neumann_imp(v, static_cast(x), tag_type(), pol), "boost::math::cyl_neumann<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type cyl_neumann(T1 v, T2 x) +{ + return cyl_neumann(v, x, policies::policy<>()); +} + +template +inline typename detail::bessel_traits::result_type sph_neumann(unsigned v, T x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename detail::bessel_traits::result_type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::sph_neumann_imp(v, static_cast(x), pol), "boost::math::sph_neumann<%1%>(%1%,%1%)"); +} + +template +inline typename detail::bessel_traits >::result_type sph_neumann(unsigned v, T x) +{ + return sph_neumann(v, x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_BESSEL_HPP diff --git a/include/boost/math/special_functions/beta.hpp b/include/boost/math/special_functions/beta.hpp new file mode 100644 index 000000000..5add7d874 --- /dev/null +++ b/include/boost/math/special_functions/beta.hpp @@ -0,0 +1,1350 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_BETA_HPP +#define BOOST_MATH_SPECIAL_BETA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ + +namespace detail{ + +// +// Implementation of Beta(a,b) using the Lanczos approximation: +// +template +T beta_imp(T a, T b, const L&, const Policy& pol) +{ + BOOST_MATH_STD_USING // for ADL of std names + + if(a <= 0) + policies::raise_domain_error("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + policies::raise_domain_error("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol); + + T result; + + T prefix = 1; + T c = a + b; + + // Special cases: + if((c == a) && (b < tools::epsilon())) + return boost::math::tgamma(b, pol); + else if((c == b) && (a < tools::epsilon())) + return boost::math::tgamma(a, pol); + if(b == 1) + return 1/a; + else if(a == 1) + return 1/b; + + /* + // + // This code appears to be no longer necessary: it was + // used to offset errors introduced from the Lanczos + // approximation, but the current Lanczos approximations + // are sufficiently accurate for all z that we can ditch + // this. It remains in the file for future reference... + // + // If a or b are less than 1, shift to greater than 1: + if(a < 1) + { + prefix *= c / a; + c += 1; + a += 1; + } + if(b < 1) + { + prefix *= c / b; + c += 1; + b += 1; + } + */ + + if(a < b) + std::swap(a, b); + + // Lanczos calculation: + T agh = a + L::g() - T(0.5); + T bgh = b + L::g() - T(0.5); + T cgh = c + L::g() - T(0.5); + result = L::lanczos_sum_expG_scaled(a) * L::lanczos_sum_expG_scaled(b) / L::lanczos_sum_expG_scaled(c); + T ambh = a - T(0.5) - b; + if((fabs(b * ambh) < (cgh * 100)) && (a > 100)) + { + // Special case where the base of the power term is close to 1 + // compute (1+x)^y instead: + result *= exp(ambh * boost::math::log1p(-b / cgh, pol)); + } + else + { + result *= pow(agh / cgh, a - T(0.5) - b); + } + if(cgh > 1e10f) + // this avoids possible overflow, but appears to be marginally less accurate: + result *= pow((agh / cgh) * (bgh / cgh), b); + else + result *= pow((agh * bgh) / (cgh * cgh), b); + result *= sqrt(boost::math::constants::e() / bgh); + + // If a and b were originally less than 1 we need to scale the result: + result *= prefix; + + return result; +} // template beta_imp(T a, T b, const L&) + +// +// Generic implementation of Beta(a,b) without Lanczos approximation support +// (Caution this is slow!!!): +// +template +T beta_imp(T a, T b, const lanczos::undefined_lanczos& /* l */, const Policy& pol) +{ + BOOST_MATH_STD_USING + + if(a <= 0) + policies::raise_domain_error("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + policies::raise_domain_error("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol); + + T result; + + T prefix = 1; + T c = a + b; + + // special cases: + if((c == a) && (b < tools::epsilon())) + return boost::math::tgamma(b, pol); + else if((c == b) && (a < tools::epsilon())) + return boost::math::tgamma(a, pol); + if(b == 1) + return 1/a; + else if(a == 1) + return 1/b; + + // shift to a and b > 1 if required: + if(a < 1) + { + prefix *= c / a; + c += 1; + a += 1; + } + if(b < 1) + { + prefix *= c / b; + c += 1; + b += 1; + } + if(a < b) + std::swap(a, b); + + // set integration limits: + T la = (std::max)(T(10), a); + T lb = (std::max)(T(10), b); + T lc = (std::max)(T(10), a+b); + + // calculate the fraction parts: + T sa = detail::lower_gamma_series(a, la, pol) / a; + sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::digits()); + T sb = detail::lower_gamma_series(b, lb, pol) / b; + sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits()); + T sc = detail::lower_gamma_series(c, lc, pol) / c; + sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits()); + + // and the exponent part: + result = exp(lc - la - lb) * pow(la/lc, a) * pow(lb/lc, b); + + // and combine: + result *= sa * sb / sc; + + // if a and b were originally less than 1 we need to scale the result: + result *= prefix; + + return result; +} // template T beta_imp(T a, T b, const lanczos::undefined_lanczos& l) + + +// +// Compute the leading power terms in the incomplete Beta: +// +// (x^a)(y^b)/Beta(a,b) when normalised, and +// (x^a)(y^b) otherwise. +// +// Almost all of the error in the incomplete beta comes from this +// function: particularly when a and b are large. Computing large +// powers are *hard* though, and using logarithms just leads to +// horrendous cancellation errors. +// +template +T ibeta_power_terms(T a, + T b, + T x, + T y, + const L&, + bool normalised, + const Policy& pol) +{ + BOOST_MATH_STD_USING + + if(!normalised) + { + // can we do better here? + return pow(x, a) * pow(y, b); + } + + T result; + + T prefix = 1; + T c = a + b; + + // combine power terms with Lanczos approximation: + T agh = a + L::g() - T(0.5); + T bgh = b + L::g() - T(0.5); + T cgh = c + L::g() - T(0.5); + result = L::lanczos_sum_expG_scaled(c) / (L::lanczos_sum_expG_scaled(a) * L::lanczos_sum_expG_scaled(b)); + + // l1 and l2 are the base of the exponents minus one: + T l1 = (x * b - y * agh) / agh; + T l2 = (y * a - x * bgh) / bgh; + if(((std::min)(fabs(l1), fabs(l2)) < 0.2)) + { + // when the base of the exponent is very near 1 we get really + // gross errors unless extra care is taken: + if((l1 * l2 > 0) || ((std::min)(a, b) < 1)) + { + // + // This first branch handles the simple cases where either: + // + // * The two power terms both go in the same direction + // (towards zero or towards infinity). In this case if either + // term overflows or underflows, then the product of the two must + // do so also. + // *Alternatively if one exponent is less than one, then we + // can't productively use it to eliminate overflow or underflow + // from the other term. Problems with spurious overflow/underflow + // can't be ruled out in this case, but it is *very* unlikely + // since one of the power terms will evaluate to a number close to 1. + // + if(fabs(l1) < 0.1) + result *= exp(a * boost::math::log1p(l1, pol)); + else + result *= pow((x * cgh) / agh, a); + if(fabs(l2) < 0.1) + result *= exp(b * boost::math::log1p(l2, pol)); + else + result *= pow((y * cgh) / bgh, b); + } + else if((std::max)(fabs(l1), fabs(l2)) < 0.5) + { + // + // Both exponents are near one and both the exponents are + // greater than one and further these two + // power terms tend in opposite directions (one towards zero, + // the other towards infinity), so we have to combine the terms + // to avoid any risk of overflow or underflow. + // + // We do this by moving one power term inside the other, we have: + // + // (1 + l1)^a * (1 + l2)^b + // = ((1 + l1)*(1 + l2)^(b/a))^a + // = (1 + l1 + l3 + l1*l3)^a ; l3 = (1 + l2)^(b/a) - 1 + // = exp((b/a) * log(1 + l2)) - 1 + // + // The tricky bit is deciding which term to move inside :-) + // By preference we move the larger term inside, so that the + // size of the largest exponent is reduced. However, that can + // only be done as long as l3 (see above) is also small. + // + bool small_a = a < b; + T ratio = b / a; + if((small_a && (ratio * l2 < 0.1)) || (!small_a && (l1 / ratio > 0.1))) + { + T l3 = boost::math::expm1(ratio * boost::math::log1p(l2, pol), pol); + l3 = l1 + l3 + l3 * l1; + l3 = a * boost::math::log1p(l3, pol); + result *= exp(l3); + } + else + { + T l3 = boost::math::expm1(boost::math::log1p(l1, pol) / ratio, pol); + l3 = l2 + l3 + l3 * l2; + l3 = b * boost::math::log1p(l3, pol); + result *= exp(l3); + } + } + else if(fabs(l1) < fabs(l2)) + { + // First base near 1 only: + T l = a * boost::math::log1p(l1, pol) + + b * log((y * cgh) / bgh); + result *= exp(l); + } + else + { + // Second base near 1 only: + T l = b * boost::math::log1p(l2, pol) + + a * log((x * cgh) / agh); + result *= exp(l); + } + } + else + { + // general case: + T b1 = (x * cgh) / agh; + T b2 = (y * cgh) / bgh; + T l1 = a * log(b1); + T l2 = b * log(b2); + if((l1 >= tools::log_max_value()) + || (l1 <= tools::log_min_value()) + || (l2 >= tools::log_max_value()) + || (l2 <= tools::log_min_value()) + ) + { + // Oops, overflow, sidestep: + if(a < b) + result *= pow(pow(b2, b/a) * b1, a); + else + result *= pow(pow(b1, a/b) * b2, b); + } + else + { + // finally the normal case: + result *= pow(b1, a) * pow(b2, b); + } + } + // combine with the leftover terms from the Lanczos approximation: + result *= sqrt(bgh / boost::math::constants::e()); + result *= sqrt(agh / cgh); + result *= prefix; + + return result; +} +// +// Compute the leading power terms in the incomplete Beta: +// +// (x^a)(y^b)/Beta(a,b) when normalised, and +// (x^a)(y^b) otherwise. +// +// Almost all of the error in the incomplete beta comes from this +// function: particularly when a and b are large. Computing large +// powers are *hard* though, and using logarithms just leads to +// horrendous cancellation errors. +// +// This version is generic, slow, and does not use the Lanczos approximation. +// +template +T ibeta_power_terms(T a, + T b, + T x, + T y, + const boost::math::lanczos::undefined_lanczos&, + bool normalised, + const Policy& pol) +{ + BOOST_MATH_STD_USING + + if(!normalised) + { + return pow(x, a) * pow(y, b); + } + + T result; + + T prefix = 1; + T c = a + b; + + // integration limits for the gamma functions: + //T la = (std::max)(T(10), a); + //T lb = (std::max)(T(10), b); + //T lc = (std::max)(T(10), a+b); + T la = a + 5; + T lb = b + 5; + T lc = a + b + 5; + // gamma function partials: + T sa = detail::lower_gamma_series(a, la, pol) / a; + sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::digits()); + T sb = detail::lower_gamma_series(b, lb, pol) / b; + sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits()); + T sc = detail::lower_gamma_series(c, lc, pol) / c; + sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits()); + // gamma function powers combined with incomplete beta powers: + + T b1 = (x * lc) / la; + T b2 = (y * lc) / lb; + T e1 = lc - la - lb; + T lb1 = a * log(b1); + T lb2 = b * log(b2); + + if((lb1 >= tools::log_max_value()) + || (lb1 <= tools::log_min_value()) + || (lb2 >= tools::log_max_value()) + || (lb2 <= tools::log_min_value()) + || (e1 >= tools::log_max_value()) + || (e1 <= tools::log_min_value()) + ) + { + result = exp(lb1 + lb2 - e1); + } + else + { + T p1, p2; + if((fabs(b1 - 1) * a < 10) && (a > 1)) + p1 = exp(a * boost::math::log1p((x * b - y * la) / la, pol)); + else + p1 = pow(b1, a); + if((fabs(b2 - 1) * b < 10) && (b > 1)) + p2 = exp(b * boost::math::log1p((y * a - x * lb) / lb, pol)); + else + p2 = pow(b2, b); + T p3 = exp(e1); + result = p1 * p2 / p3; + } + // and combine with the remaining gamma function components: + result /= sa * sb / sc; + + return result; +} +// +// Series approximation to the incomplete beta: +// +template +struct ibeta_series_t +{ + typedef T result_type; + ibeta_series_t(T a_, T b_, T x_, T mult) : result(mult), x(x_), apn(a_), poch(1-b_), n(1) {} + T operator()() + { + T r = result / apn; + apn += 1; + result *= poch * x / n; + ++n; + poch += 1; + return r; + } +private: + T result, x, apn, poch; + int n; +}; + +template +T ibeta_series(T a, T b, T x, T s0, const L&, bool normalised, T* p_derivative, T y, const Policy& pol) +{ + BOOST_MATH_STD_USING + + T result; + + BOOST_ASSERT((p_derivative == 0) || normalised); + + if(normalised) + { + T c = a + b; + + // incomplete beta power term, combined with the Lanczos approximation: + T agh = a + L::g() - T(0.5); + T bgh = b + L::g() - T(0.5); + T cgh = c + L::g() - T(0.5); + result = L::lanczos_sum_expG_scaled(c) / (L::lanczos_sum_expG_scaled(a) * L::lanczos_sum_expG_scaled(b)); + if(a * b < bgh * 10) + result *= exp((b - 0.5f) * boost::math::log1p(a / bgh, pol)); + else + result *= pow(cgh / bgh, b - 0.5f); + result *= pow(x * cgh / agh, a); + result *= sqrt(agh / boost::math::constants::e()); + + if(p_derivative) + { + *p_derivative = result * pow(y, b); + BOOST_ASSERT(*p_derivative >= 0); + } + } + else + { + // Non-normalised, just compute the power: + result = pow(x, a); + } + if(result < tools::min_value()) + return s0; // Safeguard: series can't cope with denorms. + ibeta_series_t s(a, b, x, result); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter, s0); + policies::check_series_iterations("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (with lanczos)", max_iter, pol); + return result; +} +// +// Incomplete Beta series again, this time without Lanczos support: +// +template +T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol) +{ + BOOST_MATH_STD_USING + + T result; + BOOST_ASSERT((p_derivative == 0) || normalised); + + if(normalised) + { + T prefix = 1; + T c = a + b; + + // figure out integration limits for the gamma function: + //T la = (std::max)(T(10), a); + //T lb = (std::max)(T(10), b); + //T lc = (std::max)(T(10), a+b); + T la = a + 5; + T lb = b + 5; + T lc = a + b + 5; + + // calculate the gamma parts: + T sa = detail::lower_gamma_series(a, la, pol) / a; + sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::digits()); + T sb = detail::lower_gamma_series(b, lb, pol) / b; + sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits()); + T sc = detail::lower_gamma_series(c, lc, pol) / c; + sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits()); + + // and their combined power-terms: + T b1 = (x * lc) / la; + T b2 = lc/lb; + T e1 = lc - la - lb; + T lb1 = a * log(b1); + T lb2 = b * log(b2); + + if((lb1 >= tools::log_max_value()) + || (lb1 <= tools::log_min_value()) + || (lb2 >= tools::log_max_value()) + || (lb2 <= tools::log_min_value()) + || (e1 >= tools::log_max_value()) + || (e1 <= tools::log_min_value()) ) + { + T p = lb1 + lb2 - e1; + result = exp(p); + } + else + { + result = pow(b1, a); + if(a * b < lb * 10) + result *= exp(b * boost::math::log1p(a / lb, pol)); + else + result *= pow(b2, b); + result /= exp(e1); + } + // and combine the results: + result /= sa * sb / sc; + + if(p_derivative) + { + *p_derivative = result * pow(y, b); + BOOST_ASSERT(*p_derivative >= 0); + } + } + else + { + // Non-normalised, just compute the power: + result = pow(x, a); + } + if(result < tools::min_value()) + return s0; // Safeguard: series can't cope with denorms. + ibeta_series_t s(a, b, x, result); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + result = boost::math::tools::sum_series(s, boost::math::policies::digits(), max_iter, s0); + policies::check_series_iterations("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (without lanczos)", max_iter, pol); + return result; +} + +// +// Continued fraction for the incomplete beta: +// +template +struct ibeta_fraction2_t +{ + typedef std::pair result_type; + + ibeta_fraction2_t(T a_, T b_, T x_) : a(a_), b(b_), x(x_), m(0) {} + + result_type operator()() + { + T aN = (a + m - 1) * (a + b + m - 1) * m * (b - m) * x * x; + T denom = (a + 2 * m - 1); + aN /= denom * denom; + + T bN = m; + bN += (m * (b - m) * x) / (a + 2*m - 1); + bN += ((a + m) * (a - (a + b) * x + 1 + m *(2 - x))) / (a + 2*m + 1); + + ++m; + + return std::make_pair(aN, bN); + } + +private: + T a, b, x; + int m; +}; +// +// Evaluate the incomplete beta via the continued fraction representation: +// +template +inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative) +{ + typedef typename lanczos::lanczos::type lanczos_type; + BOOST_MATH_STD_USING + T result = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol); + if(p_derivative) + { + *p_derivative = result; + BOOST_ASSERT(*p_derivative >= 0); + } + if(result == 0) + return result; + + ibeta_fraction2_t f(a, b, x); + T fract = boost::math::tools::continued_fraction_b(f, boost::math::policies::digits()); + return result / fract; +} +// +// Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x): +// +template +T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative) +{ + typedef typename lanczos::lanczos::type lanczos_type; + T prefix = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol); + if(p_derivative) + { + *p_derivative = prefix; + BOOST_ASSERT(*p_derivative >= 0); + } + prefix /= a; + if(prefix == 0) + return prefix; + T sum = 1; + T term = 1; + // series summation from 0 to k-1: + for(int i = 0; i < k-1; ++i) + { + term *= (a+b+i) * x / (a+i+1); + sum += term; + } + prefix *= sum; + + return prefix; +} +// +// This function is only needed for the non-regular incomplete beta, +// it computes the delta in: +// beta(a,b,x) = prefix + delta * beta(a+k,b,x) +// it is currently only called for small k. +// +template +inline T rising_factorial_ratio(T a, T b, int k) +{ + // calculate: + // (a)(a+1)(a+2)...(a+k-1) + // _______________________ + // (b)(b+1)(b+2)...(b+k-1) + + // This is only called with small k, for large k + // it is grossly inefficient, do not use outside it's + // intended purpose!!! + if(k == 0) + return 1; + T result = 1; + for(int i = 0; i < k; ++i) + result *= (a+i) / (b+i); + return result; +} +// +// Routine for a > 15, b < 1 +// +// Begin by figuring out how large our table of Pn's should be, +// quoted accuracies are "guestimates" based on empiracal observation. +// Note that the table size should never exceed the size of our +// tables of factorials. +// +template +struct Pn_size +{ + // This is likely to be enough for ~35-50 digit accuracy + // but it's hard to quantify exactly: + BOOST_STATIC_CONSTANT(unsigned, value = 50); + BOOST_STATIC_ASSERT(::boost::math::max_factorial::value >= 100); +}; +template <> +struct Pn_size +{ + BOOST_STATIC_CONSTANT(unsigned, value = 15); // ~8-15 digit accuracy + BOOST_STATIC_ASSERT(::boost::math::max_factorial::value >= 30); +}; +template <> +struct Pn_size +{ + BOOST_STATIC_CONSTANT(unsigned, value = 30); // 16-20 digit accuracy + BOOST_STATIC_ASSERT(::boost::math::max_factorial::value >= 60); +}; +template <> +struct Pn_size +{ + BOOST_STATIC_CONSTANT(unsigned, value = 50); // ~35-50 digit accuracy + BOOST_STATIC_ASSERT(::boost::math::max_factorial::value >= 100); +}; + +template +T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised) +{ + typedef typename lanczos::lanczos::type lanczos_type; + BOOST_MATH_STD_USING + // + // This is DiDonato and Morris's BGRAT routine, see Eq's 9 through 9.6. + // + // Some values we'll need later, these are Eq 9.1: + // + T bm1 = b - 1; + T t = a + bm1 / 2; + T lx, u; + if(y < 0.35) + lx = boost::math::log1p(-y, pol); + else + lx = log(x); + u = -t * lx; + // and from from 9.2: + T prefix; + T h = regularised_gamma_prefix(b, u, pol, lanczos_type()); + if(h <= tools::min_value()) + return s0; + if(normalised) + { + prefix = h / boost::math::tgamma_delta_ratio(a, b, pol); + prefix /= pow(t, b); + } + else + { + prefix = full_igamma_prefix(b, u, pol) / pow(t, b); + } + prefix *= mult; + // + // now we need the quantity Pn, unfortunatately this is computed + // recursively, and requires a full history of all the previous values + // so no choice but to declare a big table and hope it's big enough... + // + T p[ ::boost::math::detail::Pn_size::value ] = { 1 }; // see 9.3. + // + // Now an initial value for J, see 9.6: + // + T j = boost::math::gamma_q(b, u, pol) / h; + // + // Now we can start to pull things together and evaluate the sum in Eq 9: + // + T sum = s0 + prefix * j; // Value at N = 0 + // some variables we'll need: + unsigned tnp1 = 1; // 2*N+1 + T lx2 = lx / 2; + lx2 *= lx2; + T lxp = 1; + T t4 = 4 * t * t; + T b2n = b; + + for(unsigned n = 1; n < sizeof(p)/sizeof(p[0]); ++n) + { + /* + // debugging code, enable this if you want to determine whether + // the table of Pn's is large enough... + // + static int max_count = 2; + if(n > max_count) + { + max_count = n; + std::cerr << "Max iterations in BGRAT was " << n << std::endl; + } + */ + // + // begin by evaluating the next Pn from Eq 9.4: + // + tnp1 += 2; + p[n] = 0; + T mbn = b - n; + unsigned tmp1 = 3; + for(unsigned m = 1; m < n; ++m) + { + mbn = m * b - n; + p[n] += mbn * p[n-m] / boost::math::unchecked_factorial(tmp1); + tmp1 += 2; + } + p[n] /= n; + p[n] += bm1 / boost::math::unchecked_factorial(tnp1); + // + // Now we want Jn from Jn-1 using Eq 9.6: + // + j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4; + lxp *= lx2; + b2n += 2; + // + // pull it together with Eq 9: + // + T r = prefix * p[n] * j; + sum += r; + if(r > 1) + { + if(fabs(r) < fabs(tools::epsilon() * sum)) + break; + } + else + { + if(fabs(r / tools::epsilon()) < fabs(sum)) + break; + } + } + return sum; +} // template T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const L& l, bool normalised) + +// +// For integer arguments we can relate the incomplete beta to the +// complement of the binomial distribution cdf and use this finite sum. +// +template +inline T binomial_ccdf(T n, T k, T x, T y) +{ + BOOST_MATH_STD_USING // ADL of std names + T result = pow(x, n); + T term = result; + for(unsigned i = tools::real_cast(n - 1); i > k; --i) + { + term *= ((i + 1) * y) / ((n - i) * x) ; + result += term; + } + + return result; +} + + +// +// The incomplete beta function implementation: +// This is just a big bunch of spagetti code to divide up the +// input range and select the right implementation method for +// each domain: +// +template +T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative) +{ + static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)"; + typedef typename lanczos::lanczos::type lanczos_type; + BOOST_MATH_STD_USING // for ADL of std math functions. + + bool invert = inv; + T fract; + T y = 1 - x; + + BOOST_ASSERT((p_derivative == 0) || normalised); + + if(p_derivative) + *p_derivative = -1; // value not set. + + if(normalised) + { + // extend to a few very special cases: + if((a == 0) && (b != 0)) + return inv ? 0 : 1; + else if(b == 0) + return inv ? 1 : 0; + } + + if(a <= 0) + policies::raise_domain_error(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + policies::raise_domain_error(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol); + if((x < 0) || (x > 1)) + policies::raise_domain_error(function, "Parameter x outside the range [0,1] in the incomplete beta function (got x=%1%).", x, pol); + + if(x == 0) + { + if(p_derivative) + { + *p_derivative = (a == 1) ? 1 : (a < 1) ? tools::max_value() / 2 : tools::min_value() * 2; + } + return (invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0); + } + if(x == 1) + { + if(p_derivative) + { + *p_derivative = (b == 1) ? 1 : (b < 1) ? tools::max_value() / 2 : tools::min_value() * 2; + } + return (invert == 0 ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0); + } + + if((std::min)(a, b) <= 1) + { + if(x > 0.5) + { + std::swap(a, b); + std::swap(x, y); + invert = !invert; + } + if((std::max)(a, b) <= 1) + { + // Both a,b < 1: + if((a >= (std::min)(T(0.2), b)) || (pow(x, a) <= 0.9)) + { + if(!invert) + fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol); + } + } + else + { + std::swap(a, b); + std::swap(x, y); + invert = !invert; + if(y >= 0.3) + { + if(!invert) + fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol); + } + } + else + { + // Sidestep on a, and then use the series representation: + T prefix; + if(!normalised) + { + prefix = rising_factorial_ratio(a+b, a, 20); + } + else + { + prefix = 1; + } + fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative); + if(!invert) + fract = beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised); + else + { + fract -= (normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised); + } + } + } + } + else + { + // One of a, b < 1 only: + if((b <= 1) || ((x < 0.1) && (pow(b * x, a) <= 0.7))) + { + if(!invert) + fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol); + } + } + else + { + std::swap(a, b); + std::swap(x, y); + invert = !invert; + + if(y >= 0.3) + { + if(!invert) + fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol); + } + } + else if(a >= 15) + { + if(!invert) + fract = beta_small_b_large_a_series(a, b, x, y, T(0), T(1), pol, normalised); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -beta_small_b_large_a_series(a, b, x, y, fract, T(1), pol, normalised); + } + } + else + { + // Sidestep to improve errors: + T prefix; + if(!normalised) + { + prefix = rising_factorial_ratio(a+b, a, 20); + } + else + { + prefix = 1; + } + fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative); + if(!invert) + fract = beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised); + else + { + fract -= (normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised); + } + } + } + } + } + else + { + // Both a,b >= 1: + T lambda; + if(a < b) + { + lambda = a - (a + b) * x; + } + else + { + lambda = (a + b) * y - b; + } + if(lambda < 0) + { + std::swap(a, b); + std::swap(x, y); + invert = !invert; + } + + if(b < 40) + { + if((floor(a) == a) && (floor(b) == b)) + { + // relate to the binomial distribution and use a finite sum: + T k = a - 1; + T n = b + k; + fract = binomial_ccdf(n, k, x, y); + if(!normalised) + fract *= boost::math::beta(a, b, pol); + } + else if(b * x <= 0.7) + { + if(!invert) + fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol); + else + { + fract = -(normalised ? 1 : boost::math::beta(a, b, pol)); + invert = false; + fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol); + } + } + else if(a > 15) + { + // sidestep so we can use the series representation: + int n = static_cast(boost::math::tools::real_cast(floor(b))); + if(n == b) + --n; + T bbar = b - n; + T prefix; + if(!normalised) + { + prefix = rising_factorial_ratio(a+bbar, bbar, n); + } + else + { + prefix = 1; + } + fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast(0)); + fract = beta_small_b_large_a_series(a, bbar, x, y, fract, T(1), pol, normalised); + fract /= prefix; + } + else if(normalised) + { + // the formula here for the non-normalised case is tricky to figure + // out (for me!!), and requires two pochhammer calculations rather + // than one, so leave it for now.... + int n = static_cast(boost::math::tools::real_cast(floor(b))); + T bbar = b - n; + if(bbar <= 0) + { + --n; + bbar += 1; + } + fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast(0)); + fract += ibeta_a_step(a, bbar, x, y, 20, pol, normalised, static_cast(0)); + if(invert) + fract -= (normalised ? 1 : boost::math::beta(a, b, pol)); + //fract = ibeta_series(a+20, bbar, x, fract, l, normalised, p_derivative, y); + fract = beta_small_b_large_a_series(a+20, bbar, x, y, fract, T(1), pol, normalised); + if(invert) + { + fract = -fract; + invert = false; + } + } + else + fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative); + } + else + fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative); + } + if(p_derivative) + { + if(*p_derivative < 0) + { + *p_derivative = ibeta_power_terms(a, b, x, y, lanczos_type(), true, pol); + } + T div = y * x; + + if(*p_derivative != 0) + { + if((tools::max_value() * div < *p_derivative)) + { + // overflow, return an arbitarily large value: + *p_derivative = tools::max_value() / 2; + } + else + { + *p_derivative /= div; + } + } + } + return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract; +} // template T ibeta_imp(T a, T b, T x, const L& l, bool inv, bool normalised) + +template +inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised) +{ + return ibeta_imp(a, b, x, pol, inv, normalised, static_cast(0)); +} + +template +T ibeta_derivative_imp(T a, T b, T x, const Policy& pol) +{ + static const char* function = "ibeta_derivative<%1%>(%1%,%1%,%1%)"; + // + // start with the usual error checks: + // + if(a <= 0) + policies::raise_domain_error(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + policies::raise_domain_error(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol); + if((x < 0) || (x > 1)) + policies::raise_domain_error(function, "Parameter x outside the range [0,1] in the incomplete beta function (got x=%1%).", x, pol); + // + // Now the corner cases: + // + if(x == 0) + { + return (a > 1) ? 0 : + (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error(function, 0, pol); + } + else if(x == 1) + { + return (b > 1) ? 0 : + (b == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error(function, 0, pol); + } + // + // Now the regular cases: + // + typedef typename lanczos::lanczos::type lanczos_type; + T f1 = ibeta_power_terms(a, b, x, 1 - x, lanczos_type(), true, pol); + T y = (1 - x) * x; + + if(f1 == 0) + return 0; + + if((tools::max_value() * y < f1)) + { + // overflow: + return policies::raise_overflow_error(function, 0, pol); + } + + f1 /= y; + + return f1; +} +// +// Some forwarding functions that dis-ambiguate the third argument type: +// +template +inline typename tools::promote_args::type + beta(RT1 a, RT2 b, const Policy&, const mpl::true_*) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::beta_imp(static_cast(a), static_cast(b), evaluation_type(), forwarding_policy()), "boost::math::beta<%1%>(%1%,%1%)"); +} +template +inline typename tools::promote_args::type + beta(RT1 a, RT2 b, RT3 x, const mpl::false_*) +{ + return boost::math::beta(a, b, x, policies::policy<>()); +} +} // namespace detail + +// +// The actual function entry-points now follow, these just figure out +// which Lanczos approximation to use +// and forward to the implementation functions: +// +template +inline typename tools::promote_args::type + beta(RT1 a, RT2 b, A arg) +{ + typedef typename policies::is_policy::type tag; + return boost::math::detail::beta(a, b, arg, static_cast(0)); +} + +template +inline typename tools::promote_args::type + beta(RT1 a, RT2 b) +{ + return boost::math::beta(a, b, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + beta(RT1 a, RT2 b, RT3 x, const Policy&) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, false), "boost::math::beta<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + betac(RT1 a, RT2 b, RT3 x, const Policy&) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, false), "boost::math::betac<%1%>(%1%,%1%,%1%)"); +} +template +inline typename tools::promote_args::type + betac(RT1 a, RT2 b, RT3 x) +{ + return boost::math::betac(a, b, x, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibeta(RT1 a, RT2 b, RT3 x, const Policy&) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, true), "boost::math::ibeta<%1%>(%1%,%1%,%1%)"); +} +template +inline typename tools::promote_args::type + ibeta(RT1 a, RT2 b, RT3 x) +{ + return boost::math::ibeta(a, b, x, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibetac(RT1 a, RT2 b, RT3 x, const Policy&) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, true), "boost::math::ibetac<%1%>(%1%,%1%,%1%)"); +} +template +inline typename tools::promote_args::type + ibetac(RT1 a, RT2 b, RT3 x) +{ + return boost::math::ibetac(a, b, x, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::ibeta_derivative_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy()), "boost::math::ibeta_derivative<%1%>(%1%,%1%,%1%)"); +} +template +inline typename tools::promote_args::type + ibeta_derivative(RT1 a, RT2 b, RT3 x) +{ + return boost::math::ibeta_derivative(a, b, x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#include +#include + +#endif // BOOST_MATH_SPECIAL_BETA_HPP + + + + diff --git a/include/boost/math/special_functions/binomial.hpp b/include/boost/math/special_functions/binomial.hpp new file mode 100644 index 000000000..74f8da018 --- /dev/null +++ b/include/boost/math/special_functions/binomial.hpp @@ -0,0 +1,75 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_BINOMIAL_HPP +#define BOOST_MATH_SF_BINOMIAL_HPP + +#include +#include +#include + +namespace boost{ namespace math{ + +template +T binomial_coefficient(unsigned n, unsigned k, const Policy& pol) +{ + BOOST_MATH_STD_USING + static const char* function = "boost::math::binomial_coefficient<%1%>(unsigned, unsigned)"; + if(k > n) + return policies::raise_domain_error( + function, + "The binomial coefficient is undefined for k > n, but got k = %1%.", + k, pol); + T result; + if((k == 0) || (k == n)) + return 1; + if((k == 1) || (k == n-1)) + return n; + + if(n <= max_factorial::value) + { + // Use fast table lookup: + result = unchecked_factorial(n); + result /= unchecked_factorial(n-k); + result /= unchecked_factorial(k); + } + else + { + // Use the beta function: + if(k < n - k) + result = k * beta(static_cast(k), static_cast(n-k+1), pol); + else + result = (n - k) * beta(static_cast(k+1), static_cast(n-k), pol); + if(result == 0) + return policies::raise_overflow_error(function, 0, pol); + result = 1 / result; + } + // convert to nearest integer: + return ceil(result - 0.5f); +} +// +// Type float can only store the first 35 factorials, in order to +// increase the chance that we can use a table driven implementation +// we'll promote to double: +// +template <> +inline float binomial_coefficient >(unsigned n, unsigned k, const policies::policy<>& pol) +{ + return policies::checked_narrowing_cast >(binomial_coefficient(n, k, pol), "boost::math::binomial_coefficient<%1%>(unsigned,unsigned)"); +} + +template +inline T binomial_coefficient(unsigned n, unsigned k) +{ + return binomial_coefficient(n, k, policies::policy<>()); +} + +} // namespace math +} // namespace boost + + +#endif // BOOST_MATH_SF_BINOMIAL_HPP + + diff --git a/include/boost/math/special_functions/cbrt.hpp b/include/boost/math/special_functions/cbrt.hpp new file mode 100644 index 000000000..d8c9ad4e6 --- /dev/null +++ b/include/boost/math/special_functions/cbrt.hpp @@ -0,0 +1,72 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_CBRT_HPP +#define BOOST_MATH_SF_CBRT_HPP + +#include +#include + +namespace boost{ namespace math{ + +namespace detail +{ + + template + struct cbrt_functor + { + cbrt_functor(T const& target) : a(target){} + std::tr1::tuple operator()(T const& z) + { + T sqr = z * z; + return std::tr1::make_tuple(sqr * z - a, 3 * sqr, 6 * z); + } + private: + T a; + }; + +template +T cbrt_imp(T z, const Policy&) +{ + BOOST_MATH_STD_USING + int i_exp, sign(1); + if(z < 0) + { + z = -z; + sign = -sign; + } + if(z == 0) + return 0; + + frexp(z, &i_exp); + T min = static_cast(ldexp(0.5, i_exp/3)); + T max = static_cast(ldexp(2.0, i_exp/3)); + T guess = static_cast(ldexp(1.0, i_exp/3)); + int digits = (policies::digits()) / 2; + return sign * tools::halley_iterate(detail::cbrt_functor(z), guess, min, max, digits); +} + +} // namespace detail + +template +inline typename tools::promote_args::type cbrt(T z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::cbrt_imp(result_type(z), pol); +} + +template +inline typename tools::promote_args::type cbrt(T z) +{ + return cbrt(z, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SF_CBRT_HPP + + + diff --git a/include/boost/math/special_functions/cos_pi.hpp b/include/boost/math/special_functions/cos_pi.hpp new file mode 100644 index 000000000..ad877a7af --- /dev/null +++ b/include/boost/math/special_functions/cos_pi.hpp @@ -0,0 +1,64 @@ +// Copyright (c) 2007 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_COS_PI_HPP +#define BOOST_MATH_COS_PI_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +template +T cos_pi_imp(T x) +{ + BOOST_MATH_STD_USING // ADL of std names + // cos of pi*x: + bool invert = false; + if(x < 0.5) + return cos(constants::pi() * x); + if(x < 1) + { + x = -x; + } + + T rem = floor(x); + if(tools::real_cast(rem) & 1) + invert = !invert; + rem = x - rem; + if(rem > 0.5f) + { + rem = 1 - rem; + invert = !invert; + } + if(rem == 0.5f) + return 0; + + rem = cos(constants::pi() * rem); + return invert ? -rem : rem; +} + +} + +template +inline typename tools::promote_args::type cos_pi(T x, const Policy&) +{ + typedef typename tools::promote_args::type result_type; + return boost::math::detail::cos_pi_imp(x); +} + +template +inline typename tools::promote_args::type cos_pi(T x) +{ + typedef typename tools::promote_args::type result_type; + return boost::math::detail::cos_pi_imp(x); +} + +} // namespace math +} // namespace boost +#endif diff --git a/include/boost/math/special_functions/detail/bessel_i0.hpp b/include/boost/math/special_functions/detail/bessel_i0.hpp new file mode 100644 index 000000000..dde226e0f --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_i0.hpp @@ -0,0 +1,96 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_I0_HPP +#define BOOST_MATH_BESSEL_I0_HPP + +#include +#include + +// Modified Bessel function of the first kind of order zero +// minimax rational approximations on intervals, see +// Blair and Edwards, Chalk River Report AECL-4928, 1974 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_i0(T x) +{ + static const T P1[] = { + static_cast(-2.2335582639474375249e+15L), + static_cast(-5.5050369673018427753e+14L), + static_cast(-3.2940087627407749166e+13L), + static_cast(-8.4925101247114157499e+11L), + static_cast(-1.1912746104985237192e+10L), + static_cast(-1.0313066708737980747e+08L), + static_cast(-5.9545626019847898221e+05L), + static_cast(-2.4125195876041896775e+03L), + static_cast(-7.0935347449210549190e+00L), + static_cast(-1.5453977791786851041e-02L), + static_cast(-2.5172644670688975051e-05L), + static_cast(-3.0517226450451067446e-08L), + static_cast(-2.6843448573468483278e-11L), + static_cast(-1.5982226675653184646e-14L), + static_cast(-5.2487866627945699800e-18L), + }; + static const T Q1[] = { + static_cast(-2.2335582639474375245e+15L), + static_cast(7.8858692566751002988e+12L), + static_cast(-1.2207067397808979846e+10L), + static_cast(1.0377081058062166144e+07L), + static_cast(-4.8527560179962773045e+03L), + static_cast(1.0L), + }; + static const T P2[] = { + static_cast(-2.2210262233306573296e-04L), + static_cast(1.3067392038106924055e-02L), + static_cast(-4.4700805721174453923e-01L), + static_cast(5.5674518371240761397e+00L), + static_cast(-2.3517945679239481621e+01L), + static_cast(3.1611322818701131207e+01L), + static_cast(-9.6090021968656180000e+00L), + }; + static const T Q2[] = { + static_cast(-5.5194330231005480228e-04L), + static_cast(3.2547697594819615062e-02L), + static_cast(-1.1151759188741312645e+00L), + static_cast(1.3982595353892851542e+01L), + static_cast(-6.0228002066743340583e+01L), + static_cast(8.5539563258012929600e+01L), + static_cast(-3.1446690275135491500e+01L), + static_cast(1.0L), + }; + T value, factor, r; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + if (x < 0) + { + x = -x; // even function + } + if (x == 0) + { + return static_cast(1); + } + if (x <= 15) // x in (0, 15] + { + T y = x * x; + value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y); + } + else // x in (15, \infty) + { + T y = 1 / x - T(1) / 15; + r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y); + factor = exp(x) / sqrt(x); + value = factor * r; + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_I0_HPP diff --git a/include/boost/math/special_functions/detail/bessel_i1.hpp b/include/boost/math/special_functions/detail/bessel_i1.hpp new file mode 100644 index 000000000..928b47510 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_i1.hpp @@ -0,0 +1,99 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_I1_HPP +#define BOOST_MATH_BESSEL_I1_HPP + +#include +#include + +// Modified Bessel function of the first kind of order one +// minimax rational approximations on intervals, see +// Blair and Edwards, Chalk River Report AECL-4928, 1974 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_i1(T x) +{ + static const T P1[] = { + static_cast(-1.4577180278143463643e+15L), + static_cast(-1.7732037840791591320e+14L), + static_cast(-6.9876779648010090070e+12L), + static_cast(-1.3357437682275493024e+11L), + static_cast(-1.4828267606612366099e+09L), + static_cast(-1.0588550724769347106e+07L), + static_cast(-5.1894091982308017540e+04L), + static_cast(-1.8225946631657315931e+02L), + static_cast(-4.7207090827310162436e-01L), + static_cast(-9.1746443287817501309e-04L), + static_cast(-1.3466829827635152875e-06L), + static_cast(-1.4831904935994647675e-09L), + static_cast(-1.1928788903603238754e-12L), + static_cast(-6.5245515583151902910e-16L), + static_cast(-1.9705291802535139930e-19L), + }; + static const T Q1[] = { + static_cast(-2.9154360556286927285e+15L), + static_cast(9.7887501377547640438e+12L), + static_cast(-1.4386907088588283434e+10L), + static_cast(1.1594225856856884006e+07L), + static_cast(-5.1326864679904189920e+03L), + static_cast(1.0L), + }; + static const T P2[] = { + static_cast(1.4582087408985668208e-05L), + static_cast(-8.9359825138577646443e-04L), + static_cast(2.9204895411257790122e-02L), + static_cast(-3.4198728018058047439e-01L), + static_cast(1.3960118277609544334e+00L), + static_cast(-1.9746376087200685843e+00L), + static_cast(8.5591872901933459000e-01L), + static_cast(-6.0437159056137599999e-02L), + }; + static const T Q2[] = { + static_cast(3.7510433111922824643e-05L), + static_cast(-2.2835624489492512649e-03L), + static_cast(7.4212010813186530069e-02L), + static_cast(-8.5017476463217924408e-01L), + static_cast(3.2593714889036996297e+00L), + static_cast(-3.8806586721556593450e+00L), + static_cast(1.0L), + }; + T value, factor, r, w; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + w = abs(x); + if (x == 0) + { + return static_cast(0); + } + if (w <= 15) // w in (0, 15] + { + T y = x * x; + r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y); + factor = w; + value = factor * r; + } + else // w in (15, \infty) + { + T y = 1 / w - T(1) / 15; + r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y); + factor = exp(w) / sqrt(w); + value = factor * r; + } + + if (x < 0) + { + value *= -value; // odd function + } + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_I1_HPP diff --git a/include/boost/math/special_functions/detail/bessel_ik.hpp b/include/boost/math/special_functions/detail/bessel_ik.hpp new file mode 100644 index 000000000..c20a6641f --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_ik.hpp @@ -0,0 +1,331 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_IK_HPP +#define BOOST_MATH_BESSEL_IK_HPP + +#include +#include +#include +#include +#include + +// Modified Bessel functions of the first and second kind of fractional order + +namespace boost { namespace math { + +namespace detail { + +// Calculate K(v, x) and K(v+1, x) by method analogous to +// Temme, Journal of Computational Physics, vol 21, 343 (1976) +template +int temme_ik(T v, T x, T* K, T* K1, const Policy& pol) +{ + T f, h, p, q, coef, sum, sum1, tolerance; + T a, b, c, d, sigma, gamma1, gamma2; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + + // |x| <= 2, Temme series converge rapidly + // |x| > 2, the larger the |x|, the slower the convergence + BOOST_ASSERT(abs(x) <= 2); + BOOST_ASSERT(abs(v) <= 0.5f); + + T gp = boost::math::tgamma1pm1(v, pol); + T gm = boost::math::tgamma1pm1(-v, pol); + + a = log(x / 2); + b = exp(v * a); + sigma = -a * v; + c = abs(v) < tools::epsilon() ? + 1 : boost::math::sin_pi(v) / (v * pi()); + d = abs(sigma) < tools::epsilon() ? + 1 : sinh(sigma) / sigma; + gamma1 = abs(v) < tools::epsilon() ? + -euler() : (0.5f / v) * (gp - gm) * c; + gamma2 = (2 + gp + gm) * c / 2; + + // initial values + p = (gp + 1) / (2 * b); + q = (1 + gm) * b / 2; + f = (cosh(sigma) * gamma1 + d * (-a) * gamma2) / c; + h = p; + coef = 1; + sum = coef * f; + sum1 = coef * h; + + // series summation + tolerance = tools::epsilon(); + for (k = 1; k < policies::get_max_series_iterations(); k++) + { + f = (k * f + p + q) / (k*k - v*v); + p /= k - v; + q /= k + v; + h = p - k * f; + coef *= x * x / (4 * k); + sum += coef * f; + sum1 += coef * h; + if (abs(coef * f) < abs(sum) * tolerance) + { + break; + } + } + policies::check_series_iterations("boost::math::bessel_ik<%1%>(%1%,%1%) in temme_ik", k, pol); + + *K = sum; + *K1 = 2 * sum1 / x; + + return 0; +} + +// Evaluate continued fraction fv = I_(v+1) / I_v, derived from +// Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73 +template +int CF1_ik(T v, T x, T* fv, const Policy& pol) +{ + T C, D, f, a, b, delta, tiny, tolerance; + unsigned long k; + + BOOST_MATH_STD_USING + + // |x| <= |v|, CF1_ik converges rapidly + // |x| > |v|, CF1_ik needs O(|x|) iterations to converge + + // modified Lentz's method, see + // Lentz, Applied Optics, vol 15, 668 (1976) + tolerance = 2 * tools::epsilon(); + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + tiny = sqrt(tools::min_value()); + BOOST_MATH_INSTRUMENT_VARIABLE(tiny); + C = f = tiny; // b0 = 0, replace with tiny + D = 0; + for (k = 1; k < policies::get_max_series_iterations(); k++) + { + a = 1; + b = 2 * (v + k) / x; + C = b + a / C; + D = b + a * D; + if (C == 0) { C = tiny; } + if (D == 0) { D = tiny; } + D = 1 / D; + delta = C * D; + f *= delta; + BOOST_MATH_INSTRUMENT_VARIABLE(delta-1); + if (abs(delta - 1) <= tolerance) + { + break; + } + } + BOOST_MATH_INSTRUMENT_VARIABLE(k); + policies::check_series_iterations("boost::math::bessel_ik<%1%>(%1%,%1%) in CF1_ik", k, pol); + + *fv = f; + + return 0; +} + +// Calculate K(v, x) and K(v+1, x) by evaluating continued fraction +// z1 / z0 = U(v+1.5, 2v+1, 2x) / U(v+0.5, 2v+1, 2x), see +// Thompson and Barnett, Computer Physics Communications, vol 47, 245 (1987) +template +int CF2_ik(T v, T x, T* Kv, T* Kv1, const Policy& pol) +{ + BOOST_MATH_STD_USING + using namespace boost::math::constants; + + T S, C, Q, D, f, a, b, q, delta, tolerance, current, prev; + unsigned long k; + + // |x| >= |v|, CF2_ik converges rapidly + // |x| -> 0, CF2_ik fails to converge + + BOOST_ASSERT(abs(x) > 1); + + // Steed's algorithm, see Thompson and Barnett, + // Journal of Computational Physics, vol 64, 490 (1986) + tolerance = tools::epsilon(); + a = v * v - 0.25f; + b = 2 * (x + 1); // b1 + D = 1 / b; // D1 = 1 / b1 + f = delta = D; // f1 = delta1 = D1, coincidence + prev = 0; // q0 + current = 1; // q1 + Q = C = -a; // Q1 = C1 because q1 = 1 + S = 1 + Q * delta; // S1 + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + BOOST_MATH_INSTRUMENT_VARIABLE(a); + BOOST_MATH_INSTRUMENT_VARIABLE(b); + BOOST_MATH_INSTRUMENT_VARIABLE(D); + BOOST_MATH_INSTRUMENT_VARIABLE(f); + for (k = 2; k < policies::get_max_series_iterations(); k++) // starting from 2 + { + // continued fraction f = z1 / z0 + a -= 2 * (k - 1); + b += 2; + D = 1 / (b + a * D); + delta *= b * D - 1; + f += delta; + + // series summation S = 1 + \sum_{n=1}^{\infty} C_n * z_n / z_0 + q = (prev - (b - 2) * current) / a; + prev = current; + current = q; // forward recurrence for q + C *= -a / k; + Q += C * q; + S += Q * delta; + + // S converges slower than f + BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta); + BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance); + if (abs(Q * delta) < abs(S) * tolerance) + { + break; + } + } + policies::check_series_iterations("boost::math::bessel_ik<%1%>(%1%,%1%) in CF2_ik", k, pol); + + *Kv = sqrt(pi() / (2 * x)) * exp(-x) / S; + *Kv1 = *Kv * (0.5f + v + x + (v * v - 0.25f) * f) / x; + BOOST_MATH_INSTRUMENT_VARIABLE(*Kv); + BOOST_MATH_INSTRUMENT_VARIABLE(*Kv1); + + return 0; +} + +enum{ + need_i = 1, + need_k = 2 +}; + +// Compute I(v, x) and K(v, x) simultaneously by Temme's method, see +// Temme, Journal of Computational Physics, vol 19, 324 (1975) +template +int bessel_ik(T v, T x, T* I, T* K, int kind, const Policy& pol) +{ + // Kv1 = K_(v+1), fv = I_(v+1) / I_v + // Ku1 = K_(u+1), fu = I_(u+1) / I_u + T u, Iv, Kv, Kv1, Ku, Ku1, fv; + T W, current, prev, next; + bool reflect = false; + unsigned n, k; + BOOST_MATH_INSTRUMENT_VARIABLE(v); + BOOST_MATH_INSTRUMENT_VARIABLE(x); + BOOST_MATH_INSTRUMENT_VARIABLE(kind); + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + static const char* function = "boost::math::bessel_ik<%1%>(%1%,%1%)"; + + if (v < 0) + { + reflect = true; + v = -v; // v is non-negative from here + kind |= need_k; + } + n = tools::real_cast(v + 0.5f); + u = v - n; // -1/2 <= u < 1/2 + BOOST_MATH_INSTRUMENT_VARIABLE(n); + BOOST_MATH_INSTRUMENT_VARIABLE(u); + + if (x < 0) + { + *I = *K = policies::raise_domain_error(function, + "Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol); + return 1; + } + if (x == 0) + { + Iv = (v == 0) ? static_cast(1) : static_cast(0); + if(kind & need_k) + { + Kv = policies::raise_overflow_error(function, 0, pol); + } + else + { + Kv = std::numeric_limits::quiet_NaN(); // any value will do + } + + if(reflect && (kind & need_i)) + { + T z = (u + n % 2); + Iv = boost::math::sin_pi(z, pol) == 0 ? + Iv : + policies::raise_overflow_error(function, 0, pol); // reflection formula + } + + *I = Iv; + *K = Kv; + return 0; + } + + // x is positive until reflection + W = 1 / x; // Wronskian + if (x <= 2) // x in (0, 2] + { + temme_ik(u, x, &Ku, &Ku1, pol); // Temme series + } + else // x in (2, \infty) + { + CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik + } + prev = Ku; + current = Ku1; + for (k = 1; k <= n; k++) // forward recurrence for K + { + next = 2 * (u + k) * current / x + prev; + prev = current; + current = next; + } + Kv = prev; + Kv1 = current; + if(kind & need_i) + { + T lim = (4 * v * v + 10) / (8 * x); + lim *= lim; + lim *= lim; + lim /= 24; + if((lim < tools::epsilon() * 10) && (x > 100)) + { + // x is huge compared to v, CF1 may be very slow + // to converge so use asymptotic expansion for large + // x case instead. Note that the asymptotic expansion + // isn't very accurate - so it's deliberately very hard + // to get here - probably we're going to overflow: + Iv = asymptotic_bessel_i_large_x(v, x, pol); + } + else + { + CF1_ik(v, x, &fv, pol); // continued fraction CF1_ik + Iv = W / (Kv * fv + Kv1); // Wronskian relation + } + } + else + Iv = std::numeric_limits::quiet_NaN(); // any value will do + + if (reflect) + { + T z = (u + n % 2); + *I = Iv + (2 / pi()) * boost::math::sin_pi(z) * Kv; // reflection formula + *K = Kv; + } + else + { + *I = Iv; + *K = Kv; + } + BOOST_MATH_INSTRUMENT_VARIABLE(*I); + BOOST_MATH_INSTRUMENT_VARIABLE(*K); + return 0; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_IK_HPP diff --git a/include/boost/math/special_functions/detail/bessel_j0.hpp b/include/boost/math/special_functions/detail/bessel_j0.hpp new file mode 100644 index 000000000..9191dccb5 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_j0.hpp @@ -0,0 +1,147 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_J0_HPP +#define BOOST_MATH_BESSEL_J0_HPP + +#include +#include +#include + +// Bessel function of the first kind of order zero +// x <= 8, minimax rational approximations on root-bracketing intervals +// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_j0(T x) +{ + static const T P1[] = { + static_cast(-4.1298668500990866786e+11L), + static_cast(2.7282507878605942706e+10L), + static_cast(-6.2140700423540120665e+08L), + static_cast(6.6302997904833794242e+06L), + static_cast(-3.6629814655107086448e+04L), + static_cast(1.0344222815443188943e+02L), + static_cast(-1.2117036164593528341e-01L) + }; + static const T Q1[] = { + static_cast(2.3883787996332290397e+12L), + static_cast(2.6328198300859648632e+10L), + static_cast(1.3985097372263433271e+08L), + static_cast(4.5612696224219938200e+05L), + static_cast(9.3614022392337710626e+02L), + static_cast(1.0L), + static_cast(0.0L) + }; + static const T P2[] = { + static_cast(-1.8319397969392084011e+03L), + static_cast(-1.2254078161378989535e+04L), + static_cast(-7.2879702464464618998e+03L), + static_cast(1.0341910641583726701e+04L), + static_cast(1.1725046279757103576e+04L), + static_cast(4.4176707025325087628e+03L), + static_cast(7.4321196680624245801e+02L), + static_cast(4.8591703355916499363e+01L) + }; + static const T Q2[] = { + static_cast(-3.5783478026152301072e+05L), + static_cast(2.4599102262586308984e+05L), + static_cast(-8.4055062591169562211e+04L), + static_cast(1.8680990008359188352e+04L), + static_cast(-2.9458766545509337327e+03L), + static_cast(3.3307310774649071172e+02L), + static_cast(-2.5258076240801555057e+01L), + static_cast(1.0L) + }; + static const T PC[] = { + static_cast(2.2779090197304684302e+04L), + static_cast(4.1345386639580765797e+04L), + static_cast(2.1170523380864944322e+04L), + static_cast(3.4806486443249270347e+03L), + static_cast(1.5376201909008354296e+02L), + static_cast(8.8961548424210455236e-01L) + }; + static const T QC[] = { + static_cast(2.2779090197304684318e+04L), + static_cast(4.1370412495510416640e+04L), + static_cast(2.1215350561880115730e+04L), + static_cast(3.5028735138235608207e+03L), + static_cast(1.5711159858080893649e+02L), + static_cast(1.0L) + }; + static const T PS[] = { + static_cast(-8.9226600200800094098e+01L), + static_cast(-1.8591953644342993800e+02L), + static_cast(-1.1183429920482737611e+02L), + static_cast(-2.2300261666214198472e+01L), + static_cast(-1.2441026745835638459e+00L), + static_cast(-8.8033303048680751817e-03L) + }; + static const T QS[] = { + static_cast(5.7105024128512061905e+03L), + static_cast(1.1951131543434613647e+04L), + static_cast(7.2642780169211018836e+03L), + static_cast(1.4887231232283756582e+03L), + static_cast(9.0593769594993125859e+01L), + static_cast(1.0L) + }; + static const T x1 = static_cast(2.4048255576957727686e+00L), + x2 = static_cast(5.5200781102863106496e+00L), + x11 = static_cast(6.160e+02L), + x12 = static_cast(-1.42444230422723137837e-03L), + x21 = static_cast(1.4130e+03L), + x22 = static_cast(5.46860286310649596604e-04L); + + T value, factor, r, rc, rs; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + if (x < 0) + { + x = -x; // even function + } + if (x == 0) + { + return static_cast(1); + } + if (x <= 4) // x in (0, 4] + { + T y = x * x; + BOOST_ASSERT(sizeof(P1) == sizeof(Q1)); + r = evaluate_rational(P1, Q1, y); + factor = (x + x1) * ((x - x11/256) - x12); + value = factor * r; + } + else if (x <= 8.0) // x in (4, 8] + { + T y = 1 - (x * x)/64; + BOOST_ASSERT(sizeof(P2) == sizeof(Q2)); + r = evaluate_rational(P2, Q2, y); + factor = (x + x2) * ((x - x21/256) - x22); + value = factor * r; + } + else // x in (8, \infty) + { + T y = 8 / x; + T y2 = y * y; + T z = x - 0.25f * pi(); + BOOST_ASSERT(sizeof(PC) == sizeof(QC)); + BOOST_ASSERT(sizeof(PS) == sizeof(QS)); + rc = evaluate_rational(PC, QC, y2); + rs = evaluate_rational(PS, QS, y2); + factor = sqrt(2 / (x * pi())); + value = factor * (rc * cos(z) - y * rs * sin(z)); + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_J0_HPP diff --git a/include/boost/math/special_functions/detail/bessel_j1.hpp b/include/boost/math/special_functions/detail/bessel_j1.hpp new file mode 100644 index 000000000..906f2a8a4 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_j1.hpp @@ -0,0 +1,152 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_J1_HPP +#define BOOST_MATH_BESSEL_J1_HPP + +#include +#include +#include + +// Bessel function of the first kind of order one +// x <= 8, minimax rational approximations on root-bracketing intervals +// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968 + +namespace boost { namespace math{ namespace detail{ + +template +T bessel_j1(T x) +{ + static const T P1[] = { + static_cast(-1.4258509801366645672e+11L), + static_cast(6.6781041261492395835e+09L), + static_cast(-1.1548696764841276794e+08L), + static_cast(9.8062904098958257677e+05L), + static_cast(-4.4615792982775076130e+03L), + static_cast(1.0650724020080236441e+01L), + static_cast(-1.0767857011487300348e-02L) + }; + static const T Q1[] = { + static_cast(4.1868604460820175290e+12L), + static_cast(4.2091902282580133541e+10L), + static_cast(2.0228375140097033958e+08L), + static_cast(5.9117614494174794095e+05L), + static_cast(1.0742272239517380498e+03L), + static_cast(1.0L), + static_cast(0.0L) + }; + static const T P2[] = { + static_cast(-1.7527881995806511112e+16L), + static_cast(1.6608531731299018674e+15L), + static_cast(-3.6658018905416665164e+13L), + static_cast(3.5580665670910619166e+11L), + static_cast(-1.8113931269860667829e+09L), + static_cast(5.0793266148011179143e+06L), + static_cast(-7.5023342220781607561e+03L), + static_cast(4.6179191852758252278e+00L) + }; + static const T Q2[] = { + static_cast(1.7253905888447681194e+18L), + static_cast(1.7128800897135812012e+16L), + static_cast(8.4899346165481429307e+13L), + static_cast(2.7622777286244082666e+11L), + static_cast(6.4872502899596389593e+08L), + static_cast(1.1267125065029138050e+06L), + static_cast(1.3886978985861357615e+03L), + static_cast(1.0L) + }; + static const T PC[] = { + static_cast(-4.4357578167941278571e+06L), + static_cast(-9.9422465050776411957e+06L), + static_cast(-6.6033732483649391093e+06L), + static_cast(-1.5235293511811373833e+06L), + static_cast(-1.0982405543459346727e+05L), + static_cast(-1.6116166443246101165e+03L), + static_cast(0.0L) + }; + static const T QC[] = { + static_cast(-4.4357578167941278568e+06L), + static_cast(-9.9341243899345856590e+06L), + static_cast(-6.5853394797230870728e+06L), + static_cast(-1.5118095066341608816e+06L), + static_cast(-1.0726385991103820119e+05L), + static_cast(-1.4550094401904961825e+03L), + static_cast(1.0L) + }; + static const T PS[] = { + static_cast(3.3220913409857223519e+04L), + static_cast(8.5145160675335701966e+04L), + static_cast(6.6178836581270835179e+04L), + static_cast(1.8494262873223866797e+04L), + static_cast(1.7063754290207680021e+03L), + static_cast(3.5265133846636032186e+01L), + static_cast(0.0L) + }; + static const T QS[] = { + static_cast(7.0871281941028743574e+05L), + static_cast(1.8194580422439972989e+06L), + static_cast(1.4194606696037208929e+06L), + static_cast(4.0029443582266975117e+05L), + static_cast(3.7890229745772202641e+04L), + static_cast(8.6383677696049909675e+02L), + static_cast(1.0L) + }; + static const T x1 = static_cast(3.8317059702075123156e+00L), + x2 = static_cast(7.0155866698156187535e+00L), + x11 = static_cast(9.810e+02L), + x12 = static_cast(-3.2527979248768438556e-04L), + x21 = static_cast(1.7960e+03L), + x22 = static_cast(-3.8330184381246462950e-05L); + + T value, factor, r, rc, rs, w; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + w = abs(x); + if (x == 0) + { + return static_cast(0); + } + if (w <= 4) // w in (0, 4] + { + T y = x * x; + BOOST_ASSERT(sizeof(P1) == sizeof(Q1)); + r = evaluate_rational(P1, Q1, y); + factor = w * (w + x1) * ((w - x11/256) - x12); + value = factor * r; + } + else if (w <= 8) // w in (4, 8] + { + T y = x * x; + BOOST_ASSERT(sizeof(P2) == sizeof(Q2)); + r = evaluate_rational(P2, Q2, y); + factor = w * (w + x2) * ((w - x21/256) - x22); + value = factor * r; + } + else // w in (8, \infty) + { + T y = 8 / w; + T y2 = y * y; + T z = w - 0.75f * pi(); + BOOST_ASSERT(sizeof(PC) == sizeof(QC)); + BOOST_ASSERT(sizeof(PS) == sizeof(QS)); + rc = evaluate_rational(PC, QC, y2); + rs = evaluate_rational(PS, QS, y2); + factor = sqrt(2 / (w * pi())); + value = factor * (rc * cos(z) - y * rs * sin(z)); + } + + if (x < 0) + { + value *= -1; // odd function + } + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_J1_HPP diff --git a/include/boost/math/special_functions/detail/bessel_jn.hpp b/include/boost/math/special_functions/detail/bessel_jn.hpp new file mode 100644 index 000000000..cf89d28ce --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_jn.hpp @@ -0,0 +1,86 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_JN_HPP +#define BOOST_MATH_BESSEL_JN_HPP + +#include +#include +#include + +// Bessel function of the first kind of integer order +// J_n(z) is the minimal solution +// n < abs(z), forward recurrence stable and usable +// n >= abs(z), forward recurrence unstable, use Miller's algorithm + +namespace boost { namespace math { namespace detail{ + +template +T bessel_jn(int n, T x, const Policy& pol) +{ + T value(0), factor, current, prev, next; + + BOOST_MATH_STD_USING + + if (n == 0) + { + return bessel_j0(x); + } + if (n == 1) + { + return bessel_j1(x); + } + if (n < 0) + { + factor = (n & 0x1) ? -1 : 1; // J_{-n}(z) = (-1)^n J_n(z) + n = -n; + } + else + { + factor = 1; + } + + if (x == 0) // n >= 2 + { + return static_cast(0); + } + + if (n < abs(x)) // forward recurrence + { + prev = bessel_j0(x); + current = bessel_j1(x); + for (int k = 1; k < n; k++) + { + value = 2 * k * current / x - prev; + prev = current; + current = value; + } + } + else // backward recurrence + { + T fn; int s; // fn = J_(n+1) / J_n + // |x| <= n, fast convergence for continued fraction CF1 + boost::math::detail::CF1_jy(static_cast(n), x, &fn, &s, pol); + // tiny initial value to prevent overflow + T init = sqrt(tools::min_value()); + prev = fn * init; + current = init; + for (int k = n; k > 0; k--) + { + next = 2 * k * current / x - prev; + prev = current; + current = next; + } + T ratio = init / current; // scaling ratio + value = bessel_j0(x) * ratio; // normalization + } + value *= factor; + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_JN_HPP diff --git a/include/boost/math/special_functions/detail/bessel_jy.hpp b/include/boost/math/special_functions/detail/bessel_jy.hpp new file mode 100644 index 000000000..9ef303ec6 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_jy.hpp @@ -0,0 +1,361 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_JY_HPP +#define BOOST_MATH_BESSEL_JY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Bessel functions of the first and second kind of fractional order + +namespace boost { namespace math { + +namespace detail { + +// Calculate Y(v, x) and Y(v+1, x) by Temme's method, see +// Temme, Journal of Computational Physics, vol 21, 343 (1976) +template +int temme_jy(T v, T x, T* Y, T* Y1, const Policy& pol) +{ + T g, h, p, q, f, coef, sum, sum1, tolerance; + T a, d, e, sigma; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + BOOST_ASSERT(fabs(v) <= 0.5f); // precondition for using this routine + + T gp = boost::math::tgamma1pm1(v, pol); + T gm = boost::math::tgamma1pm1(-v, pol); + T spv = boost::math::sin_pi(v, pol); + T spv2 = boost::math::sin_pi(v/2, pol); + T xp = pow(x/2, v); + + a = log(x / 2); + sigma = -a * v; + d = abs(sigma) < tools::epsilon() ? + T(1) : sinh(sigma) / sigma; + e = abs(v) < tools::epsilon() ? v*pi()*pi() / 2 + : 2 * spv2 * spv2 / v; + + T g1 = (v == 0) ? -euler() : (gp - gm) / ((1 + gp) * (1 + gm) * 2 * v); + T g2 = (2 + gp + gm) / ((1 + gp) * (1 + gm) * 2); + T vspv = (fabs(v) < tools::epsilon()) ? 1/constants::pi() : v / spv; + f = (g1 * cosh(sigma) - g2 * a * d) * 2 * vspv; + + p = vspv / (xp * (1 + gm)); + q = vspv * xp / (1 + gp); + + g = f + e * q; + h = p; + coef = 1; + sum = coef * g; + sum1 = coef * h; + + T v2 = v * v; + T coef_mult = -x * x / 4; + + // series summation + tolerance = tools::epsilon(); + for (k = 1; k < policies::get_max_series_iterations(); k++) + { + f = (k * f + p + q) / (k*k - v2); + p /= k - v; + q /= k + v; + g = f + e * q; + h = p - k * g; + coef *= coef_mult / k; + sum += coef * g; + sum1 += coef * h; + if (abs(coef * g) < abs(sum) * tolerance) + { + break; + } + } + policies::check_series_iterations("boost::math::bessel_jy<%1%>(%1%,%1%) in temme_jy", k, pol); + *Y = -sum; + *Y1 = -2 * sum1 / x; + + return 0; +} + +// Evaluate continued fraction fv = J_(v+1) / J_v, see +// Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73 +template +int CF1_jy(T v, T x, T* fv, int* sign, const Policy& pol) +{ + T C, D, f, a, b, delta, tiny, tolerance; + unsigned long k; + int s = 1; + + BOOST_MATH_STD_USING + + // |x| <= |v|, CF1_jy converges rapidly + // |x| > |v|, CF1_jy needs O(|x|) iterations to converge + + // modified Lentz's method, see + // Lentz, Applied Optics, vol 15, 668 (1976) + tolerance = 2 * tools::epsilon(); + tiny = sqrt(tools::min_value()); + C = f = tiny; // b0 = 0, replace with tiny + D = 0.0L; + for (k = 1; k < policies::get_max_series_iterations() * 100; k++) + { + a = -1; + b = 2 * (v + k) / x; + C = b + a / C; + D = b + a * D; + if (C == 0) { C = tiny; } + if (D == 0) { D = tiny; } + D = 1 / D; + delta = C * D; + f *= delta; + if (D < 0) { s = -s; } + if (abs(delta - 1.0L) < tolerance) + { break; } + } + policies::check_series_iterations("boost::math::bessel_jy<%1%>(%1%,%1%) in CF1_jy", k / 100, pol); + *fv = -f; + *sign = s; // sign of denominator + + return 0; +} + +template +struct complex_trait +{ + typedef typename mpl::if_, + std::complex, sc::simple_complex >::type type; +}; + +// Evaluate continued fraction p + iq = (J' + iY') / (J + iY), see +// Press et al, Numerical Recipes in C, 2nd edition, 1992 +template +int CF2_jy(T v, T x, T* p, T* q, const Policy& pol) +{ + BOOST_MATH_STD_USING + + typedef typename complex_trait::type complex_type; + + complex_type C, D, f, a, b, delta, one(1); + T tiny, zero(0.0L); + unsigned long k; + + // |x| >= |v|, CF2_jy converges rapidly + // |x| -> 0, CF2_jy fails to converge + BOOST_ASSERT(fabs(x) > 1); + + // modified Lentz's method, complex numbers involved, see + // Lentz, Applied Optics, vol 15, 668 (1976) + T tolerance = 2 * tools::epsilon(); + tiny = sqrt(tools::min_value()); + C = f = complex_type(-0.5f/x, 1.0L); + D = 0; + for (k = 1; k < policies::get_max_series_iterations(); k++) + { + a = (k - 0.5f)*(k - 0.5f) - v*v; + if (k == 1) + { + a *= complex_type(T(0), 1/x); + } + b = complex_type(2*x, T(2*k)); + C = b + a / C; + D = b + a * D; + if (C == zero) { C = tiny; } + if (D == zero) { D = tiny; } + D = one / D; + delta = C * D; + f *= delta; + if (abs(delta - one) < tolerance) { break; } + } + policies::check_series_iterations("boost::math::bessel_jy<%1%>(%1%,%1%) in CF2_jy", k, pol); + *p = real(f); + *q = imag(f); + + return 0; +} + +enum +{ + need_j = 1, need_y = 2 +}; + +// Compute J(v, x) and Y(v, x) simultaneously by Steed's method, see +// Barnett et al, Computer Physics Communications, vol 8, 377 (1974) +template +int bessel_jy(T v, T x, T* J, T* Y, int kind, const Policy& pol) +{ + BOOST_ASSERT(x >= 0); + + T u, Jv, Ju, Yv, Yv1, Yu, Yu1(0), fv, fu; + T W, p, q, gamma, current, prev, next; + bool reflect = false; + unsigned n, k; + int s; + + static const char* function = "boost::math::bessel_jy<%1%>(%1%,%1%)"; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + if (v < 0) + { + reflect = true; + v = -v; // v is non-negative from here + kind = need_j|need_y; // need both for reflection formula + } + n = real_cast(v + 0.5L); + u = v - n; // -1/2 <= u < 1/2 + + if (x == 0) + { + *J = *Y = policies::raise_overflow_error( + function, 0, pol); + return 1; + } + + // x is positive until reflection + W = T(2) / (x * pi()); // Wronskian + if (x <= 2) // x in (0, 2] + { + if(temme_jy(u, x, &Yu, &Yu1, pol)) // Temme series + { + // domain error: + *J = *Y = Yu; + return 1; + } + prev = Yu; + current = Yu1; + for (k = 1; k <= n; k++) // forward recurrence for Y + { + next = 2 * (u + k) * current / x - prev; + prev = current; + current = next; + } + Yv = prev; + Yv1 = current; + if(kind&need_j) + { + CF1_jy(v, x, &fv, &s, pol); // continued fraction CF1_jy + Jv = W / (Yv * fv - Yv1); // Wronskian relation + } + else + Jv = std::numeric_limits::quiet_NaN(); // any value will do, we're not using it. + } + else // x in (2, \infty) + { + // Get Y(u, x): + // define tag type that will dispatch to right limits: + typedef typename bessel_asymptotic_tag::type tag_type; + + T lim; + switch(kind) + { + case need_j: + lim = asymptotic_bessel_j_limit(v, tag_type()); + break; + case need_y: + lim = asymptotic_bessel_y_limit(tag_type()); + break; + default: + lim = (std::max)( + asymptotic_bessel_j_limit(v, tag_type()), + asymptotic_bessel_y_limit(tag_type())); + break; + } + if(x > lim) + { + if(kind&need_y) + { + Yu = asymptotic_bessel_y_large_x_2(u, x); + Yu1 = asymptotic_bessel_y_large_x_2(u + 1, x); + } + else + Yu = std::numeric_limits::quiet_NaN(); // any value will do, we're not using it. + if(kind&need_j) + { + Jv = asymptotic_bessel_j_large_x_2(v, x); + } + else + Jv = std::numeric_limits::quiet_NaN(); // any value will do, we're not using it. + } + else + { + CF1_jy(v, x, &fv, &s, pol); + // tiny initial value to prevent overflow + T init = sqrt(tools::min_value()); + prev = fv * s * init; + current = s * init; + for (k = n; k > 0; k--) // backward recurrence for J + { + next = 2 * (u + k) * current / x - prev; + prev = current; + current = next; + } + T ratio = (s * init) / current; // scaling ratio + // can also call CF1_jy() to get fu, not much difference in precision + fu = prev / current; + CF2_jy(u, x, &p, &q, pol); // continued fraction CF2_jy + T t = u / x - fu; // t = J'/J + gamma = (p - t) / q; + Ju = sign(current) * sqrt(W / (q + gamma * (p - t))); + + Jv = Ju * ratio; // normalization + + Yu = gamma * Ju; + Yu1 = Yu * (u/x - p - q/gamma); + } + if(kind&need_y) + { + // compute Y: + prev = Yu; + current = Yu1; + for (k = 1; k <= n; k++) // forward recurrence for Y + { + next = 2 * (u + k) * current / x - prev; + prev = current; + current = next; + } + Yv = prev; + } + else + Yv = std::numeric_limits::quiet_NaN(); // any value will do, we're not using it. + } + + if (reflect) + { + T z = (u + n % 2); + *J = boost::math::cos_pi(z, pol) * Jv - boost::math::sin_pi(z, pol) * Yv; // reflection formula + *Y = boost::math::sin_pi(z, pol) * Jv + boost::math::cos_pi(z, pol) * Yv; + } + else + { + *J = Jv; + *Y = Yv; + } + + return 0; +} + +} // namespace detail + +}} // namespaces + +#endif // BOOST_MATH_BESSEL_JY_HPP diff --git a/include/boost/math/special_functions/detail/bessel_jy_asym.hpp b/include/boost/math/special_functions/detail/bessel_jy_asym.hpp new file mode 100644 index 000000000..478c84306 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_jy_asym.hpp @@ -0,0 +1,297 @@ +// Copyright (c) 2007 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// +// This is a partial header, do not include on it's own!!! +// +// Contains asymptotic expansions for Bessel J(v,x) and Y(v,x) +// functions, as x -> INF. +// +#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP +#define BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP + +#include + +namespace boost{ namespace math{ namespace detail{ + +template +inline T asymptotic_bessel_j_large_x_P(T v, T x) +{ + // A&S 9.2.9 + T s = 1; + T mu = 4 * v * v; + T ez2 = 8 * x; + ez2 *= ez2; + s -= (mu-1) * (mu-9) / (2 * ez2); + s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2); + return s; +} + +template +inline T asymptotic_bessel_j_large_x_Q(T v, T x) +{ + // A&S 9.2.10 + T s = 0; + T mu = 4 * v * v; + T ez = 8*x; + s += (mu-1) / ez; + s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez); + return s; +} + +template +inline T asymptotic_bessel_j_large_x(T v, T x) +{ + // + // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/ + // + // Also A&S 9.2.5 + // + BOOST_MATH_STD_USING // ADL of std names + T chi = fabs(x) - constants::pi() * (2 * v + 1) / 4; + return sqrt(2 / (constants::pi() * x)) + * (asymptotic_bessel_j_large_x_P(v, x) * cos(chi) + - asymptotic_bessel_j_large_x_Q(v, x) * sin(chi)); +} + +template +inline T asymptotic_bessel_y_large_x(T v, T x) +{ + // + // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/ + // + // Also A&S 9.2.5 + // + BOOST_MATH_STD_USING // ADL of std names + T chi = fabs(x) - constants::pi() * (2 * v + 1) / 4; + return sqrt(2 / (constants::pi() * x)) + * (asymptotic_bessel_j_large_x_P(v, x) * sin(chi) + - asymptotic_bessel_j_large_x_Q(v, x) * cos(chi)); +} + +template +inline T asymptotic_bessel_amplitude(T v, T x) +{ + // Calculate the amplitude of J(v, x) and Y(v, x) for large + // x: see A&S 9.2.28. + BOOST_MATH_STD_USING + T s = 1; + T mu = 4 * v * v; + T txq = 2 * x; + txq *= txq; + + s += (mu - 1) / (2 * txq); + s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8); + s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6); + + return sqrt(s * 2 / (constants::pi() * x)); +} + +template +T asymptotic_bessel_phase_mx(T v, T x) +{ + // + // Calculate the phase of J(v, x) and Y(v, x) for large x. + // See A&S 9.2.29. + // Note that the result returned is the phase less x. + // + T mu = 4 * v * v; + T denom = 4 * x; + T denom_mult = denom * denom; + + T s = -constants::pi() * (v / 2 + 0.25f); + s += (mu - 1) / (2 * denom); + denom *= denom_mult; + s += (mu - 1) * (mu - 25) / (6 * denom); + denom *= denom_mult; + s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom); + denom *= denom_mult; + s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom); + return s; +} + +template +inline T asymptotic_bessel_y_large_x_2(T v, T x) +{ + // See A&S 9.2.19. + BOOST_MATH_STD_USING + // Get the phase and amplitude: + T ampl = asymptotic_bessel_amplitude(v, x); + T phase = asymptotic_bessel_phase_mx(v, x); + // + // Calculate the sine of the phase, using: + // sin(x+p) = sin(x)cos(p) + cos(x)sin(p) + // + T sin_phase = sin(phase) * cos(x) + cos(phase) * sin(x); + return sin_phase * ampl; +} + +template +inline T asymptotic_bessel_j_large_x_2(T v, T x) +{ + // See A&S 9.2.19. + BOOST_MATH_STD_USING + // Get the phase and amplitude: + T ampl = asymptotic_bessel_amplitude(v, x); + T phase = asymptotic_bessel_phase_mx(v, x); + // + // Calculate the sine of the phase, using: + // cos(x+p) = cos(x)cos(p) - sin(x)sin(p) + // + T sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x); + return sin_phase * ampl; +} + +// +// Various limits for the J and Y asymptotics +// (the asympotic expansions are safe to use if +// x is less than the limit given). +// We assume that if we don't use these expansions then the +// error will likely be >100eps, so the limits given are chosen +// to lead to < 100eps truncation error. +// +template +inline T asymptotic_bessel_y_limit(const mpl::int_<0>&) +{ + // default case: + BOOST_MATH_STD_USING + return 2.25 / pow(100 * tools::epsilon() / T(0.001f), T(0.2f)); +} +template +inline T asymptotic_bessel_y_limit(const mpl::int_<53>&) +{ + // double case: + return 304 /*780*/; +} +template +inline T asymptotic_bessel_y_limit(const mpl::int_<64>&) +{ + // 80-bit extended-double case: + return 1552 /*3500*/; +} +template +inline T asymptotic_bessel_y_limit(const mpl::int_<113>&) +{ + // 128-bit long double case: + return 1245243 /*3128000*/; +} + +template +struct bessel_asymptotic_tag +{ + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::or_< + mpl::equal_to >, + mpl::greater > >, + mpl::int_<0>, + typename mpl::if_< + mpl::greater >, + mpl::int_<113>, + typename mpl::if_< + mpl::greater >, + mpl::int_<64>, + mpl::int_<53> + >::type + >::type + >::type type; +}; + +template +inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&) +{ + // default case: + BOOST_MATH_STD_USING + T v2 = (std::max)(T(3), v * v); + return v2 / pow(100 * tools::epsilon() / T(2e-5f), T(0.17f)); +} +template +inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&) +{ + // double case: + T v2 = (std::max)(T(3), v * v); + return v2 * 33 /*73*/; +} +template +inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&) +{ + // 80-bit extended-double case: + T v2 = (std::max)(T(3), v * v); + return v2 * 121 /*266*/; +} +template +inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&) +{ + // 128-bit long double case: + T v2 = (std::max)(T(3), v * v); + return v2 * 39154 /*85700*/; +} + +template +void temme_asyptotic_y_small_x(T v, T x, T* Y, T* Y1, const Policy& pol) +{ + T c = 1; + T p = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, -v) / boost::math::tgamma(1 - v, pol); + T q = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, v) / boost::math::tgamma(1 + v, pol); + T f = (p - q) / v; + T g_prefix = boost::math::sin_pi(v / 2, pol); + g_prefix *= g_prefix * 2 / v; + T g = f + g_prefix * q; + T h = p; + T c_mult = -x * x / 4; + + T y(c * g), y1(c * h); + + for(int k = 1; k < policies::get_max_series_iterations(); ++k) + { + f = (k * f + p + q) / (k*k - v*v); + p /= k - v; + q /= k + v; + c *= c_mult / k; + T c1 = pow(-x * x / 4, k) / factorial(k, pol); + g = f + g_prefix * q; + h = -k * g + p; + y += c * g; + y1 += c * h; + if(c * g / tools::epsilon() < y) + break; + } + + *Y = -y; + *Y1 = (-2 / x) * y1; +} + +template +T asymptotic_bessel_i_large_x(T v, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + T s = 1; + T mu = 4 * v * v; + T ex = 8 * x; + T num = mu - 1; + T denom = ex; + + s -= num / denom; + + num *= mu - 9; + denom *= ex * 2; + s += num / denom; + + num *= mu - 25; + denom *= ex * 3; + s -= num / denom; + + // Try and avoid overflow to the last minute: + T e = exp(x/2); + + s = e * (e * s / sqrt(2 * x * constants::pi())); + + return (boost::math::isfinite)(s) ? + s : policies::raise_overflow_error("boost::math::asymptotic_bessel_i_large_x<%1%>(%1%,%1%)", 0, pol); +} + +}}} // namespaces + +#endif diff --git a/include/boost/math/special_functions/detail/bessel_k0.hpp b/include/boost/math/special_functions/detail/bessel_k0.hpp new file mode 100644 index 000000000..a86a055dc --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_k0.hpp @@ -0,0 +1,116 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_K0_HPP +#define BOOST_MATH_BESSEL_K0_HPP + +#include +#include +#include + +// Modified Bessel function of the second kind of order zero +// minimax rational approximations on intervals, see +// Russon and Blair, Chalk River Report AECL-3461, 1969 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_k0(T x, const Policy& pol) +{ + BOOST_MATH_INSTRUMENT_CODE(x); + + static const T P1[] = { + static_cast(2.4708152720399552679e+03L), + static_cast(5.9169059852270512312e+03L), + static_cast(4.6850901201934832188e+02L), + static_cast(1.1999463724910714109e+01L), + static_cast(1.3166052564989571850e-01L), + static_cast(5.8599221412826100000e-04L) + }; + static const T Q1[] = { + static_cast(2.1312714303849120380e+04L), + static_cast(-2.4994418972832303646e+02L), + static_cast(1.0L) + }; + static const T P2[] = { + static_cast(-1.6128136304458193998e+06L), + static_cast(-3.7333769444840079748e+05L), + static_cast(-1.7984434409411765813e+04L), + static_cast(-2.9501657892958843865e+02L), + static_cast(-1.6414452837299064100e+00L) + }; + static const T Q2[] = { + static_cast(-1.6128136304458193998e+06L), + static_cast(2.9865713163054025489e+04L), + static_cast(-2.5064972445877992730e+02L), + static_cast(1.0L) + }; + static const T P3[] = { + static_cast(1.1600249425076035558e+02L), + static_cast(2.3444738764199315021e+03L), + static_cast(1.8321525870183537725e+04L), + static_cast(7.1557062783764037541e+04L), + static_cast(1.5097646353289914539e+05L), + static_cast(1.7398867902565686251e+05L), + static_cast(1.0577068948034021957e+05L), + static_cast(3.1075408980684392399e+04L), + static_cast(3.6832589957340267940e+03L), + static_cast(1.1394980557384778174e+02L) + }; + static const T Q3[] = { + static_cast(9.2556599177304839811e+01L), + static_cast(1.8821890840982713696e+03L), + static_cast(1.4847228371802360957e+04L), + static_cast(5.8824616785857027752e+04L), + static_cast(1.2689839587977598727e+05L), + static_cast(1.5144644673520157801e+05L), + static_cast(9.7418829762268075784e+04L), + static_cast(3.1474655750295278825e+04L), + static_cast(4.4329628889746408858e+03L), + static_cast(2.0013443064949242491e+02L), + static_cast(1.0L) + }; + T value, factor, r, r1, r2; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::bessel_k0<%1%>(%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Got x = %1%, but argument x must be non-negative, complex number result not supported", x, pol); + } + if (x == 0) + { + return policies::raise_overflow_error(function, 0, pol); + } + if (x <= 1) // x in (0, 1] + { + T y = x * x; + r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y); + r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y); + factor = log(x); + value = r1 - factor * r2; + } + else // x in (1, \infty) + { + T y = 1 / x; + r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y); + factor = exp(-x) / sqrt(x); + value = factor * r; + BOOST_MATH_INSTRUMENT_CODE("y = " << y); + BOOST_MATH_INSTRUMENT_CODE("r = " << r); + BOOST_MATH_INSTRUMENT_CODE("factor = " << factor); + BOOST_MATH_INSTRUMENT_CODE("value = " << value); + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_K0_HPP diff --git a/include/boost/math/special_functions/detail/bessel_k1.hpp b/include/boost/math/special_functions/detail/bessel_k1.hpp new file mode 100644 index 000000000..198c3eb57 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_k1.hpp @@ -0,0 +1,112 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_K1_HPP +#define BOOST_MATH_BESSEL_K1_HPP + +#include +#include +#include + +// Modified Bessel function of the second kind of order one +// minimax rational approximations on intervals, see +// Russon and Blair, Chalk River Report AECL-3461, 1969 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_k1(T x, const Policy& pol) +{ + static const T P1[] = { + static_cast(-2.2149374878243304548e+06L), + static_cast(7.1938920065420586101e+05L), + static_cast(1.7733324035147015630e+05L), + static_cast(7.1885382604084798576e+03L), + static_cast(9.9991373567429309922e+01L), + static_cast(4.8127070456878442310e-01L) + }; + static const T Q1[] = { + static_cast(-2.2149374878243304548e+06L), + static_cast(3.7264298672067697862e+04L), + static_cast(-2.8143915754538725829e+02L), + static_cast(1.0L) + }; + static const T P2[] = { + static_cast(0.0L), + static_cast(-1.3531161492785421328e+06L), + static_cast(-1.4758069205414222471e+05L), + static_cast(-4.5051623763436087023e+03L), + static_cast(-5.3103913335180275253e+01L), + static_cast(-2.2795590826955002390e-01L) + }; + static const T Q2[] = { + static_cast(-2.7062322985570842656e+06L), + static_cast(4.3117653211351080007e+04L), + static_cast(-3.0507151578787595807e+02L), + static_cast(1.0L) + }; + static const T P3[] = { + static_cast(2.2196792496874548962e+00L), + static_cast(4.4137176114230414036e+01L), + static_cast(3.4122953486801312910e+02L), + static_cast(1.3319486433183221990e+03L), + static_cast(2.8590657697910288226e+03L), + static_cast(3.4540675585544584407e+03L), + static_cast(2.3123742209168871550e+03L), + static_cast(8.1094256146537402173e+02L), + static_cast(1.3182609918569941308e+02L), + static_cast(7.5584584631176030810e+00L), + static_cast(6.4257745859173138767e-02L) + }; + static const T Q3[] = { + static_cast(1.7710478032601086579e+00L), + static_cast(3.4552228452758912848e+01L), + static_cast(2.5951223655579051357e+02L), + static_cast(9.6929165726802648634e+02L), + static_cast(1.9448440788918006154e+03L), + static_cast(2.1181000487171943810e+03L), + static_cast(1.2082692316002348638e+03L), + static_cast(3.3031020088765390854e+02L), + static_cast(3.6001069306861518855e+01L), + static_cast(1.0L) + }; + T value, factor, r, r1, r2; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::bessel_k1<%1%>(%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol); + } + if (x == 0) + { + return policies::raise_overflow_error(function, 0, pol); + } + if (x <= 1) // x in (0, 1] + { + T y = x * x; + r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y); + r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y); + factor = log(x); + value = (r1 + factor * r2) / x; + } + else // x in (1, \infty) + { + T y = 1 / x; + r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y); + factor = exp(-x) / sqrt(x); + value = factor * r; + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_K1_HPP diff --git a/include/boost/math/special_functions/detail/bessel_kn.hpp b/include/boost/math/special_functions/detail/bessel_kn.hpp new file mode 100644 index 000000000..8d30462e8 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_kn.hpp @@ -0,0 +1,69 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_KN_HPP +#define BOOST_MATH_BESSEL_KN_HPP + +#include +#include +#include + +// Modified Bessel function of the second kind of integer order +// K_n(z) is the dominant solution, forward recurrence always OK (though unstable) + +namespace boost { namespace math { namespace detail{ + +template +T bessel_kn(int n, T x, const Policy& pol) +{ + T value, current, prev; + + using namespace boost::math::tools; + + static const char* function = "boost::math::bessel_kn<%1%>(%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol); + } + if (x == 0) + { + return policies::raise_overflow_error(function, 0, pol); + } + + if (n < 0) + { + n = -n; // K_{-n}(z) = K_n(z) + } + if (n == 0) + { + value = bessel_k0(x, pol); + } + else if (n == 1) + { + value = bessel_k1(x, pol); + } + else + { + prev = bessel_k0(x, pol); + current = bessel_k1(x, pol); + int k = 1; + BOOST_ASSERT(k < n); + do + { + value = 2 * k * current / x + prev; + prev = current; + current = value; + ++k; + } + while(k < n); + } + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_KN_HPP diff --git a/include/boost/math/special_functions/detail/bessel_y0.hpp b/include/boost/math/special_functions/detail/bessel_y0.hpp new file mode 100644 index 000000000..4e6db50dc --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_y0.hpp @@ -0,0 +1,177 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_Y0_HPP +#define BOOST_MATH_BESSEL_Y0_HPP + +#include +#include +#include +#include +#include + +// Bessel function of the second kind of order zero +// x <= 8, minimax rational approximations on root-bracketing intervals +// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_y0(T x, const Policy& pol) +{ + static const T P1[] = { + static_cast(1.0723538782003176831e+11L), + static_cast(-8.3716255451260504098e+09L), + static_cast(2.0422274357376619816e+08L), + static_cast(-2.1287548474401797963e+06L), + static_cast(1.0102532948020907590e+04L), + static_cast(-1.8402381979244993524e+01L), + }; + static const T Q1[] = { + static_cast(5.8873865738997033405e+11L), + static_cast(8.1617187777290363573e+09L), + static_cast(5.5662956624278251596e+07L), + static_cast(2.3889393209447253406e+05L), + static_cast(6.6475986689240190091e+02L), + static_cast(1.0L), + }; + static const T P2[] = { + static_cast(-2.2213976967566192242e+13L), + static_cast(-5.5107435206722644429e+11L), + static_cast(4.3600098638603061642e+10L), + static_cast(-6.9590439394619619534e+08L), + static_cast(4.6905288611678631510e+06L), + static_cast(-1.4566865832663635920e+04L), + static_cast(1.7427031242901594547e+01L), + }; + static const T Q2[] = { + static_cast(4.3386146580707264428e+14L), + static_cast(5.4266824419412347550e+12L), + static_cast(3.4015103849971240096e+10L), + static_cast(1.3960202770986831075e+08L), + static_cast(4.0669982352539552018e+05L), + static_cast(8.3030857612070288823e+02L), + static_cast(1.0L), + }; + static const T P3[] = { + static_cast(-8.0728726905150210443e+15L), + static_cast(6.7016641869173237784e+14L), + static_cast(-1.2829912364088687306e+11L), + static_cast(-1.9363051266772083678e+11L), + static_cast(2.1958827170518100757e+09L), + static_cast(-1.0085539923498211426e+07L), + static_cast(2.1363534169313901632e+04L), + static_cast(-1.7439661319197499338e+01L), + }; + static const T Q3[] = { + static_cast(3.4563724628846457519e+17L), + static_cast(3.9272425569640309819e+15L), + static_cast(2.2598377924042897629e+13L), + static_cast(8.6926121104209825246e+10L), + static_cast(2.4727219475672302327e+08L), + static_cast(5.3924739209768057030e+05L), + static_cast(8.7903362168128450017e+02L), + static_cast(1.0L), + }; + static const T PC[] = { + static_cast(2.2779090197304684302e+04L), + static_cast(4.1345386639580765797e+04L), + static_cast(2.1170523380864944322e+04L), + static_cast(3.4806486443249270347e+03L), + static_cast(1.5376201909008354296e+02L), + static_cast(8.8961548424210455236e-01L), + }; + static const T QC[] = { + static_cast(2.2779090197304684318e+04L), + static_cast(4.1370412495510416640e+04L), + static_cast(2.1215350561880115730e+04L), + static_cast(3.5028735138235608207e+03L), + static_cast(1.5711159858080893649e+02L), + static_cast(1.0L), + }; + static const T PS[] = { + static_cast(-8.9226600200800094098e+01L), + static_cast(-1.8591953644342993800e+02L), + static_cast(-1.1183429920482737611e+02L), + static_cast(-2.2300261666214198472e+01L), + static_cast(-1.2441026745835638459e+00L), + static_cast(-8.8033303048680751817e-03L), + }; + static const T QS[] = { + static_cast(5.7105024128512061905e+03L), + static_cast(1.1951131543434613647e+04L), + static_cast(7.2642780169211018836e+03L), + static_cast(1.4887231232283756582e+03L), + static_cast(9.0593769594993125859e+01L), + static_cast(1.0L), + }; + static const T x1 = static_cast(8.9357696627916752158e-01L), + x2 = static_cast(3.9576784193148578684e+00L), + x3 = static_cast(7.0860510603017726976e+00L), + x11 = static_cast(2.280e+02L), + x12 = static_cast(2.9519662791675215849e-03L), + x21 = static_cast(1.0130e+03L), + x22 = static_cast(6.4716931485786837568e-04L), + x31 = static_cast(1.8140e+03L), + x32 = static_cast(1.1356030177269762362e-04L) + ; + T value, factor, r, rc, rs; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + static const char* function = "boost::math::bessel_y0<%1%>(%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Got x = %1% but x must be non-negative, complex result not supported.", x, pol); + } + if (x == 0) + { + return -policies::raise_overflow_error(function, 0, pol); + } + if (x <= 3) // x in (0, 3] + { + T y = x * x; + T z = 2 * log(x/x1) * bessel_j0(x) / pi(); + r = evaluate_rational(P1, Q1, y); + factor = (x + x1) * ((x - x11/256) - x12); + value = z + factor * r; + } + else if (x <= 5.5f) // x in (3, 5.5] + { + T y = x * x; + T z = 2 * log(x/x2) * bessel_j0(x) / pi(); + r = evaluate_rational(P2, Q2, y); + factor = (x + x2) * ((x - x21/256) - x22); + value = z + factor * r; + } + else if (x <= 8) // x in (5.5, 8] + { + T y = x * x; + T z = 2 * log(x/x3) * bessel_j0(x) / pi(); + r = evaluate_rational(P3, Q3, y); + factor = (x + x3) * ((x - x31/256) - x32); + value = z + factor * r; + } + else // x in (8, \infty) + { + T y = 8 / x; + T y2 = y * y; + T z = x - 0.25f * pi(); + rc = evaluate_rational(PC, QC, y2); + rs = evaluate_rational(PS, QS, y2); + factor = sqrt(2 / (x * pi())); + value = factor * (rc * sin(z) + y * rs * cos(z)); + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_Y0_HPP diff --git a/include/boost/math/special_functions/detail/bessel_y1.hpp b/include/boost/math/special_functions/detail/bessel_y1.hpp new file mode 100644 index 000000000..de0bef519 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_y1.hpp @@ -0,0 +1,150 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_Y1_HPP +#define BOOST_MATH_BESSEL_Y1_HPP + +#include +#include +#include +#include +#include + +// Bessel function of the second kind of order one +// x <= 8, minimax rational approximations on root-bracketing intervals +// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968 + +namespace boost { namespace math { namespace detail{ + +template +T bessel_y1(T x, const Policy& pol) +{ + static const T P1[] = { + static_cast(4.0535726612579544093e+13L), + static_cast(5.4708611716525426053e+12L), + static_cast(-3.7595974497819597599e+11L), + static_cast(7.2144548214502560419e+09L), + static_cast(-5.9157479997408395984e+07L), + static_cast(2.2157953222280260820e+05L), + static_cast(-3.1714424660046133456e+02L), + }; + static const T Q1[] = { + static_cast(3.0737873921079286084e+14L), + static_cast(4.1272286200406461981e+12L), + static_cast(2.7800352738690585613e+10L), + static_cast(1.2250435122182963220e+08L), + static_cast(3.8136470753052572164e+05L), + static_cast(8.2079908168393867438e+02L), + static_cast(1.0L), + }; + static const T P2[] = { + static_cast(1.1514276357909013326e+19L), + static_cast(-5.6808094574724204577e+18L), + static_cast(-2.3638408497043134724e+16L), + static_cast(4.0686275289804744814e+15L), + static_cast(-5.9530713129741981618e+13L), + static_cast(3.7453673962438488783e+11L), + static_cast(-1.1957961912070617006e+09L), + static_cast(1.9153806858264202986e+06L), + static_cast(-1.2337180442012953128e+03L), + }; + static const T Q2[] = { + static_cast(5.3321844313316185697e+20L), + static_cast(5.6968198822857178911e+18L), + static_cast(3.0837179548112881950e+16L), + static_cast(1.1187010065856971027e+14L), + static_cast(3.0221766852960403645e+11L), + static_cast(6.3550318087088919566e+08L), + static_cast(1.0453748201934079734e+06L), + static_cast(1.2855164849321609336e+03L), + static_cast(1.0L), + }; + static const T PC[] = { + static_cast(-4.4357578167941278571e+06L), + static_cast(-9.9422465050776411957e+06L), + static_cast(-6.6033732483649391093e+06L), + static_cast(-1.5235293511811373833e+06L), + static_cast(-1.0982405543459346727e+05L), + static_cast(-1.6116166443246101165e+03L), + static_cast(0.0L), + }; + static const T QC[] = { + static_cast(-4.4357578167941278568e+06L), + static_cast(-9.9341243899345856590e+06L), + static_cast(-6.5853394797230870728e+06L), + static_cast(-1.5118095066341608816e+06L), + static_cast(-1.0726385991103820119e+05L), + static_cast(-1.4550094401904961825e+03L), + static_cast(1.0L), + }; + static const T PS[] = { + static_cast(3.3220913409857223519e+04L), + static_cast(8.5145160675335701966e+04L), + static_cast(6.6178836581270835179e+04L), + static_cast(1.8494262873223866797e+04L), + static_cast(1.7063754290207680021e+03L), + static_cast(3.5265133846636032186e+01L), + static_cast(0.0L), + }; + static const T QS[] = { + static_cast(7.0871281941028743574e+05L), + static_cast(1.8194580422439972989e+06L), + static_cast(1.4194606696037208929e+06L), + static_cast(4.0029443582266975117e+05L), + static_cast(3.7890229745772202641e+04L), + static_cast(8.6383677696049909675e+02L), + static_cast(1.0L), + }; + static const T x1 = static_cast(2.1971413260310170351e+00L), + x2 = static_cast(5.4296810407941351328e+00L), + x11 = static_cast(5.620e+02L), + x12 = static_cast(1.8288260310170351490e-03L), + x21 = static_cast(1.3900e+03L), + x22 = static_cast(-6.4592058648672279948e-06L) + ; + T value, factor, r, rc, rs; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + if (x <= 0) + { + return policies::raise_domain_error("bost::math::bessel_y1<%1%>(%1%,%1%)", + "Got x == %1%, but x must be > 0, complex result not supported.", x, pol); + } + if (x <= 4) // x in (0, 4] + { + T y = x * x; + T z = 2 * log(x/x1) * bessel_j1(x) / pi(); + r = evaluate_rational(P1, Q1, y); + factor = (x + x1) * ((x - x11/256) - x12) / x; + value = z + factor * r; + } + else if (x <= 8) // x in (4, 8] + { + T y = x * x; + T z = 2 * log(x/x2) * bessel_j1(x) / pi(); + r = evaluate_rational(P2, Q2, y); + factor = (x + x2) * ((x - x21/256) - x22) / x; + value = z + factor * r; + } + else // x in (8, \infty) + { + T y = 8 / x; + T y2 = y * y; + T z = x - 0.75f * pi(); + rc = evaluate_rational(PC, QC, y2); + rs = evaluate_rational(PS, QS, y2); + factor = sqrt(2 / (x * pi())); + value = factor * (rc * sin(z) + y * rs * cos(z)); + } + + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_Y1_HPP diff --git a/include/boost/math/special_functions/detail/bessel_yn.hpp b/include/boost/math/special_functions/detail/bessel_yn.hpp new file mode 100644 index 000000000..3ae9d12c5 --- /dev/null +++ b/include/boost/math/special_functions/detail/bessel_yn.hpp @@ -0,0 +1,79 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_BESSEL_YN_HPP +#define BOOST_MATH_BESSEL_YN_HPP + +#include +#include +#include + +// Bessel function of the second kind of integer order +// Y_n(z) is the dominant solution, forward recurrence always OK (though unstable) + +namespace boost { namespace math { namespace detail{ + +template +T bessel_yn(int n, T x, const Policy& pol) +{ + T value, factor, current, prev; + + using namespace boost::math::tools; + + static const char* function = "boost::math::bessel_yn<%1%>(%1%,%1%)"; + + if ((x == 0) && (n == 0)) + { + return -policies::raise_overflow_error(function, 0, pol); + } + if (x <= 0) + { + return policies::raise_domain_error(function, + "Got x = %1%, but x must be > 0, complex result not supported.", x, pol); + } + + // + // Reflection comes first: + // + if (n < 0) + { + factor = (n & 0x1) ? -1 : 1; // Y_{-n}(z) = (-1)^n Y_n(z) + n = -n; + } + else + { + factor = 1; + } + + if (n == 0) + { + value = bessel_y0(x, pol); + } + else if (n == 1) + { + value = factor * bessel_y1(x, pol); + } + else + { + prev = bessel_y0(x, pol); + current = bessel_y1(x, pol); + int k = 1; + BOOST_ASSERT(k < n); + do + { + value = 2 * k * current / x - prev; + prev = current; + current = value; + ++k; + } + while(k < n); + value *= factor; + } + return value; +} + +}}} // namespaces + +#endif // BOOST_MATH_BESSEL_YN_HPP diff --git a/include/boost/math/special_functions/detail/erf_inv.hpp b/include/boost/math/special_functions/detail/erf_inv.hpp new file mode 100644 index 000000000..5d3afe5d8 --- /dev/null +++ b/include/boost/math/special_functions/detail/erf_inv.hpp @@ -0,0 +1,464 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_ERF_INV_HPP +#define BOOST_MATH_SF_ERF_INV_HPP + +namespace boost{ namespace math{ + +namespace detail{ +// +// The inverse erf and erfc functions share a common implementation, +// this version is for 80-bit long double's and smaller: +// +template +T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*) +{ + BOOST_MATH_STD_USING // for ADL of std names. + + T result = 0; + + if(p <= 0.5) + { + // + // Evaluate inverse erf using the rational approximation: + // + // x = p(p+10)(Y+R(p)) + // + // Where Y is a constant, and R(p) is optimised for a low + // absolute error compared to |Y|. + // + // double: Max error found: 2.001849e-18 + // long double: Max error found: 1.017064e-20 + // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21 + // + static const float Y = 0.0891314744949340820313f; + static const T P[] = { + -0.000508781949658280665617L, + -0.00836874819741736770379L, + 0.0334806625409744615033L, + -0.0126926147662974029034L, + -0.0365637971411762664006L, + 0.0219878681111168899165L, + 0.00822687874676915743155L, + -0.00538772965071242932965L + }; + static const T Q[] = { + 1, + -0.970005043303290640362L, + -1.56574558234175846809L, + 1.56221558398423026363L, + 0.662328840472002992063L, + -0.71228902341542847553L, + -0.0527396382340099713954L, + 0.0795283687341571680018L, + -0.00233393759374190016776L, + 0.000886216390456424707504L + }; + T g = p * (p + 10); + T r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p); + result = g * Y + g * r; + } + else if(q >= 0.25) + { + // + // Rational approximation for 0.5 > q >= 0.25 + // + // x = sqrt(-2*log(q)) / (Y + R(q)) + // + // Where Y is a constant, and R(q) is optimised for a low + // absolute error compared to Y. + // + // double : Max error found: 7.403372e-17 + // long double : Max error found: 6.084616e-20 + // Maximum Deviation Found (error term) 4.811e-20 + // + static const float Y = 2.249481201171875f; + static const T P[] = { + -0.202433508355938759655L, + 0.105264680699391713268L, + 8.37050328343119927838L, + 17.6447298408374015486L, + -18.8510648058714251895L, + -44.6382324441786960818L, + 17.445385985570866523L, + 21.1294655448340526258L, + -3.67192254707729348546L + }; + static const T Q[] = { + 1L, + 6.24264124854247537712L, + 3.9713437953343869095L, + -28.6608180499800029974L, + -20.1432634680485188801L, + 48.5609213108739935468L, + 10.8268667355460159008L, + -22.6436933413139721736L, + 1.72114765761200282724L + }; + T g = sqrt(-2 * log(q)); + T xs = q - 0.25; + T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = g / (Y + r); + } + else + { + // + // For q < 0.25 we have a series of rational approximations all + // of the general form: + // + // let: x = sqrt(-log(q)) + // + // Then the result is given by: + // + // x(Y+R(x-B)) + // + // where Y is a constant, B is the lowest value of x for which + // the approximation is valid, and R(x-B) is optimised for a low + // absolute error compared to Y. + // + // Note that almost all code will really go through the first + // or maybe second approximation. After than we're dealing with very + // small input values indeed: 80 and 128 bit long double's go all the + // way down to ~ 1e-5000 so the "tail" is rather long... + // + T x = sqrt(-log(q)); + if(x < 3) + { + // Max error found: 1.089051e-20 + static const float Y = 0.807220458984375f; + static const T P[] = { + -0.131102781679951906451L, + -0.163794047193317060787L, + 0.117030156341995252019L, + 0.387079738972604337464L, + 0.337785538912035898924L, + 0.142869534408157156766L, + 0.0290157910005329060432L, + 0.00214558995388805277169L, + -0.679465575181126350155e-6L, + 0.285225331782217055858e-7L, + -0.681149956853776992068e-9L + }; + static const T Q[] = { + 1, + 3.46625407242567245975L, + 5.38168345707006855425L, + 4.77846592945843778382L, + 2.59301921623620271374L, + 0.848854343457902036425L, + 0.152264338295331783612L, + 0.01105924229346489121L + }; + T xs = x - 1.125; + T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = Y * x + R * x; + } + else if(x < 6) + { + // Max error found: 8.389174e-21 + static const float Y = 0.93995571136474609375f; + static const T P[] = { + -0.0350353787183177984712L, + -0.00222426529213447927281L, + 0.0185573306514231072324L, + 0.00950804701325919603619L, + 0.00187123492819559223345L, + 0.000157544617424960554631L, + 0.460469890584317994083e-5L, + -0.230404776911882601748e-9L, + 0.266339227425782031962e-11L + }; + static const T Q[] = { + 1L, + 1.3653349817554063097L, + 0.762059164553623404043L, + 0.220091105764131249824L, + 0.0341589143670947727934L, + 0.00263861676657015992959L, + 0.764675292302794483503e-4L + }; + T xs = x - 3; + T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = Y * x + R * x; + } + else if(x < 18) + { + // Max error found: 1.481312e-19 + static const float Y = 0.98362827301025390625f; + static const T P[] = { + -0.0167431005076633737133L, + -0.00112951438745580278863L, + 0.00105628862152492910091L, + 0.000209386317487588078668L, + 0.149624783758342370182e-4L, + 0.449696789927706453732e-6L, + 0.462596163522878599135e-8L, + -0.281128735628831791805e-13L, + 0.99055709973310326855e-16L + }; + static const T Q[] = { + 1L, + 0.591429344886417493481L, + 0.138151865749083321638L, + 0.0160746087093676504695L, + 0.000964011807005165528527L, + 0.275335474764726041141e-4L, + 0.282243172016108031869e-6L + }; + T xs = x - 6; + T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = Y * x + R * x; + } + else if(x < 44) + { + // Max error found: 5.697761e-20 + static const float Y = 0.99714565277099609375f; + static const T P[] = { + -0.0024978212791898131227L, + -0.779190719229053954292e-5L, + 0.254723037413027451751e-4L, + 0.162397777342510920873e-5L, + 0.396341011304801168516e-7L, + 0.411632831190944208473e-9L, + 0.145596286718675035587e-11L, + -0.116765012397184275695e-17L + }; + static const T Q[] = { + 1L, + 0.207123112214422517181L, + 0.0169410838120975906478L, + 0.000690538265622684595676L, + 0.145007359818232637924e-4L, + 0.144437756628144157666e-6L, + 0.509761276599778486139e-9L + }; + T xs = x - 18; + T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = Y * x + R * x; + } + else + { + // Max error found: 1.279746e-20 + static const float Y = 0.99941349029541015625f; + static const T P[] = { + -0.000539042911019078575891L, + -0.28398759004727721098e-6L, + 0.899465114892291446442e-6L, + 0.229345859265920864296e-7L, + 0.225561444863500149219e-9L, + 0.947846627503022684216e-12L, + 0.135880130108924861008e-14L, + -0.348890393399948882918e-21L + }; + static const T Q[] = { + 1L, + 0.0845746234001899436914L, + 0.00282092984726264681981L, + 0.468292921940894236786e-4L, + 0.399968812193862100054e-6L, + 0.161809290887904476097e-8L, + 0.231558608310259605225e-11L + }; + T xs = x - 44; + T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs); + result = Y * x + R * x; + } + } + return result; +} + +template +struct erf_roots +{ + std::tr1::tuple operator()(const T& guess) + { + BOOST_MATH_STD_USING + T derivative = sign * (2 / sqrt(constants::pi())) * exp(-(guess * guess)); + T derivative2 = -2 * guess * derivative; + return std::tr1::make_tuple(((sign > 0) ? boost::math::erf(guess, Policy()) : boost::math::erfc(guess, Policy())) - target, derivative, derivative2); + } + erf_roots(T z, int s) : target(z), sign(s) {} +private: + T target; + int sign; +}; + +template +T erf_inv_imp(const T& p, const T& q, const Policy& pol, const boost::mpl::int_<0>*) +{ + // + // Generic version, get a guess that's accurate to 64-bits (10^-19) + // + T guess = erf_inv_imp(p, q, pol, static_cast const*>(0)); + T result; + // + // If T has more bit's than 64 in it's mantissa then we need to iterate, + // otherwise we can just return the result: + // + if(policies::digits() > 64) + { + if(p <= 0.5) + { + result = tools::halley_iterate(detail::erf_roots::type, Policy>(p, 1), guess, static_cast(0), tools::max_value(), (policies::digits() * 2) / 3); + } + else + { + result = tools::halley_iterate(detail::erf_roots::type, Policy>(q, -1), guess, static_cast(0), tools::max_value(), (policies::digits() * 2) / 3); + } + } + else + { + result = guess; + } + return result; +} + +} // namespace detail + +template +typename tools::promote_args::type erfc_inv(T z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + // + // Begin by testing for domain errors, and other special cases: + // + static const char* function = "boost::math::erfc_inv<%1%>(%1%, %1%)"; + if((z < 0) || (z > 2)) + policies::raise_domain_error(function, "Argument outside range [0,2] in inverse erfc function (got p=%1%).", z, pol); + if(z == 0) + return policies::raise_overflow_error(function, 0, pol); + if(z == 2) + return -policies::raise_overflow_error(function, 0, pol); + // + // Normalise the input, so it's in the range [0,1], we will + // negate the result if z is outside that range. This is a simple + // application of the erfc reflection formula: erfc(-z) = 2 - erfc(z) + // + result_type p, q, s; + if(z > 1) + { + q = 2 - z; + p = 1 - q; + s = -1; + } + else + { + p = 1 - z; + q = z; + s = 1; + } + // + // A bit of meta-programming to figure out which implementation + // to use, based on the number of bits in the mantissa of T: + // + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::or_ >, mpl::greater > >, + mpl::int_<0>, + mpl::int_<64> + >::type tag_type; + // + // Likewise use internal promotion, so we evaluate at a higher + // precision internally if it's appropriate: + // + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + // + // And get the result, negating where required: + // + return s * policies::checked_narrowing_cast( + detail::erf_inv_imp(static_cast(p), static_cast(q), forwarding_policy(), static_cast(0)), function); +} + +template +typename tools::promote_args::type erf_inv(T z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + // + // Begin by testing for domain errors, and other special cases: + // + static const char* function = "boost::math::erf_inv<%1%>(%1%, %1%)"; + if((z < -1) || (z > 1)) + policies::raise_domain_error(function, "Argument outside range [-1, 1] in inverse erf function (got p=%1%).", z, pol); + if(z == 1) + return policies::raise_overflow_error(function, 0, pol); + if(z == -1) + return -policies::raise_overflow_error(function, 0, pol); + if(z == 0) + return 0; + // + // Normalise the input, so it's in the range [0,1], we will + // negate the result if z is outside that range. This is a simple + // application of the erf reflection formula: erf(-z) = -erf(z) + // + result_type p, q, s; + if(z < 0) + { + p = -z; + q = 1 - p; + s = -1; + } + else + { + p = z; + q = 1 - z; + s = 1; + } + // + // A bit of meta-programming to figure out which implementation + // to use, based on the number of bits in the mantissa of T: + // + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::or_ >, mpl::greater > >, + mpl::int_<0>, + mpl::int_<64> + >::type tag_type; + // + // Likewise use internal promotion, so we evaluate at a higher + // precision internally if it's appropriate: + // + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + // + // Likewise use internal promotion, so we evaluate at a higher + // precision internally if it's appropriate: + // + typedef typename policies::evaluation::type eval_type; + // + // And get the result, negating where required: + // + return s * policies::checked_narrowing_cast( + detail::erf_inv_imp(static_cast(p), static_cast(q), forwarding_policy(), static_cast(0)), function); +} + +template +inline typename tools::promote_args::type erfc_inv(T z) +{ + return erfc_inv(z, policies::policy<>()); +} + +template +inline typename tools::promote_args::type erf_inv(T z) +{ + return erf_inv(z, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SF_ERF_INV_HPP diff --git a/include/boost/math/special_functions/detail/gamma_inva.hpp b/include/boost/math/special_functions/detail/gamma_inva.hpp new file mode 100644 index 000000000..8e6f90ff5 --- /dev/null +++ b/include/boost/math/special_functions/detail/gamma_inva.hpp @@ -0,0 +1,228 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// +// This is not a complete header file, it is included by gamma.hpp +// after it has defined it's definitions. This inverts the incomplete +// gamma functions P and Q on the first parameter "a" using a generic +// root finding algorithm (TOMS Algorithm 748). +// + +#ifndef BOOST_MATH_SP_DETAIL_GAMMA_INVA +#define BOOST_MATH_SP_DETAIL_GAMMA_INVA + +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +template +struct gamma_inva_t +{ + gamma_inva_t(T z_, T p_, bool invert_) : z(z_), p(p_), invert(invert_) {} + T operator()(T a) + { + return invert ? p - boost::math::gamma_q(a, z, Policy()) : boost::math::gamma_p(a, z, Policy()) - p; + } +private: + T z, p; + bool invert; +}; + +template +T inverse_poisson_cornish_fisher(T lambda, T p, T q, const Policy& pol) +{ + BOOST_MATH_STD_USING + // mean: + T m = lambda; + // standard deviation: + T sigma = sqrt(lambda); + // skewness + T sk = 1 / sigma; + // kurtosis: + // T k = 1/lambda; + // Get the inverse of a std normal distribution: + T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two(); + // Set the sign: + if(p < 0.5) + x = -x; + T x2 = x * x; + // w is correction term due to skewness + T w = x + sk * (x2 - 1) / 6; + /* + // Add on correction due to kurtosis. + // Disabled for now, seems to make things worse? + // + if(lambda >= 10) + w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36; + */ + w = m + sigma * w; + return w > tools::min_value() ? w : tools::min_value(); +} + +template +T gamma_inva_imp(const T& z, const T& p, const T& q, const Policy& pol) +{ + BOOST_MATH_STD_USING // for ADL of std lib math functions + // + // Special cases first: + // + if(p == 0) + { + return tools::max_value(); + } + if(q == 0) + { + return tools::min_value(); + } + // + // Function object, this is the functor whose root + // we have to solve: + // + gamma_inva_t f(z, (p < q) ? p : q, (p < q) ? false : true); + // + // Tolerance: full precision. + // + tools::eps_tolerance tol(policies::digits()); + // + // Now figure out a starting guess for what a may be, + // we'll start out with a value that'll put p or q + // right bang in the middle of their range, the functions + // are quite sensitive so we should need too many steps + // to bracket the root from there: + // + T guess; + T factor = 8; + if(z >= 1) + { + // + // We can use the relationship between the incomplete + // gamma function and the poisson distribution to + // calculate an approximate inverse, for large z + // this is actually pretty accurate, but it fails badly + // when z is very small. Also set our step-factor according + // to how accurate we think the result is likely to be: + // + guess = 1 + inverse_poisson_cornish_fisher(z, q, p, pol); + if(z > 5) + { + if(z > 1000) + factor = 1.01f; + else if(z > 50) + factor = 1.1f; + else if(guess > 10) + factor = 1.25f; + else + factor = 2; + if(guess < 1.1) + factor = 8; + } + } + else if(z > 0.5) + { + guess = z * 1.2f; + } + else + { + guess = -0.4f / log(z); + } + // + // Max iterations permitted: + // + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + // + // Use our generic derivative-free root finding procedure. + // We could use Newton steps here, taking the PDF of the + // Poisson distribution as our derivative, but that's + // even worse performance-wise than the generic method :-( + // + std::pair r = bracket_and_solve_root(f, guess, factor, false, tol, max_iter, pol); + if(max_iter >= policies::get_max_root_iterations()) + policies::raise_evaluation_error("boost::math::gamma_p_inva<%1%>(%1%, %1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol); + return (r.first + r.second) / 2; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + gamma_p_inva(T1 x, T2 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(p == 0) + { + return tools::max_value(); + } + if(p == 1) + { + return tools::min_value(); + } + + return policies::checked_narrowing_cast( + detail::gamma_inva_imp( + static_cast(x), + static_cast(p), + 1 - static_cast(p), + pol), "boost::math::gamma_p_inva<%1%>(%1%, %1%)"); +} + +template +inline typename tools::promote_args::type + gamma_q_inva(T1 x, T2 q, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(q == 1) + { + return tools::max_value(); + } + if(q == 0) + { + return tools::min_value(); + } + + return policies::checked_narrowing_cast( + detail::gamma_inva_imp( + static_cast(x), + 1 - static_cast(q), + static_cast(q), + pol), "boost::math::gamma_q_inva<%1%>(%1%, %1%)"); +} + +template +inline typename tools::promote_args::type + gamma_p_inva(T1 x, T2 p) +{ + return boost::math::gamma_p_inva(x, p, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + gamma_q_inva(T1 x, T2 q) +{ + return boost::math::gamma_q_inva(x, q, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SP_DETAIL_GAMMA_INVA + + diff --git a/include/boost/math/special_functions/detail/ibeta_inv_ab.hpp b/include/boost/math/special_functions/detail/ibeta_inv_ab.hpp new file mode 100644 index 000000000..ff9b1b122 --- /dev/null +++ b/include/boost/math/special_functions/detail/ibeta_inv_ab.hpp @@ -0,0 +1,319 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// +// This is not a complete header file, it is included by beta.hpp +// after it has defined it's definitions. This inverts the incomplete +// beta functions ibeta and ibetac on the first parameters "a" +// and "b" using a generic root finding algorithm (TOMS Algorithm 748). +// + +#ifndef BOOST_MATH_SP_DETAIL_BETA_INV_AB +#define BOOST_MATH_SP_DETAIL_BETA_INV_AB + +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +template +struct beta_inv_ab_t +{ + beta_inv_ab_t(T b_, T z_, T p_, bool invert_, bool swap_ab_) : b(b_), z(z_), p(p_), invert(invert_), swap_ab(swap_ab_) {} + T operator()(T a) + { + return invert ? + p - boost::math::ibetac(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) + : boost::math::ibeta(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) - p; + } +private: + T b, z, p; + bool invert, swap_ab; +}; + +template +T inverse_negative_binomial_cornish_fisher(T n, T sf, T sfc, T p, T q, const Policy& pol) +{ + BOOST_MATH_STD_USING + // mean: + T m = n * (sfc) / sf; + T t = sqrt(n * (sfc)); + // standard deviation: + T sigma = t / sf; + // skewness + T sk = (1 + sfc) / t; + // kurtosis: + T k = (6 - sf * (5+sfc)) / (n * (sfc)); + // Get the inverse of a std normal distribution: + T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two(); + // Set the sign: + if(p < 0.5) + x = -x; + T x2 = x * x; + // w is correction term due to skewness + T w = x + sk * (x2 - 1) / 6; + // + // Add on correction due to kurtosis. + // + if(n >= 10) + w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36; + + w = m + sigma * w; + if(w < tools::min_value()) + return tools::min_value(); + return w; +} + +template +T ibeta_inv_ab_imp(const T& b, const T& z, const T& p, const T& q, bool swap_ab, const Policy& pol) +{ + BOOST_MATH_STD_USING // for ADL of std lib math functions + // + // Special cases first: + // + BOOST_MATH_INSTRUMENT_CODE("b = " << b << " z = " << z << " p = " << p << " q = " << " swap = " << swap_ab); + if(p == 0) + { + return swap_ab ? tools::min_value() : tools::max_value(); + } + if(q == 0) + { + return swap_ab ? tools::max_value() : tools::min_value(); + } + // + // Function object, this is the functor whose root + // we have to solve: + // + beta_inv_ab_t f(b, z, (p < q) ? p : q, (p < q) ? false : true, swap_ab); + // + // Tolerance: full precision. + // + tools::eps_tolerance tol(policies::digits()); + // + // Now figure out a starting guess for what a may be, + // we'll start out with a value that'll put p or q + // right bang in the middle of their range, the functions + // are quite sensitive so we should need too many steps + // to bracket the root from there: + // + T guess = 0; + T factor = 5; + // + // Convert variables to parameters of a negative binomial distribution: + // + T n = b; + T sf = swap_ab ? z : 1-z; + T sfc = swap_ab ? 1-z : z; + T u = swap_ab ? p : q; + T v = swap_ab ? q : p; + if(u <= pow(sf, n)) + { + // + // Result is less than 1, negative binomial approximation + // is useless.... + // + if((p < q) != swap_ab) + { + guess = (std::min)(b * 2, T(1)); + } + else + { + guess = (std::min)(b / 2, T(1)); + } + } + if(n * n * n * u * sf > 0.005) + guess = 1 + inverse_negative_binomial_cornish_fisher(n, sf, sfc, u, v, pol); + + if(guess < 10) + { + // + // Negative binomial approximation not accurate in this area: + // + if((p < q) != swap_ab) + { + guess = (std::min)(b * 2, T(10)); + } + else + { + guess = (std::min)(b / 2, T(10)); + } + } + else + factor = (v < sqrt(tools::epsilon())) ? 2 : (guess < 20 ? 1.2f : 1.1f); + BOOST_MATH_INSTRUMENT_CODE("guess = " << guess); + // + // Max iterations permitted: + // + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + std::pair r = bracket_and_solve_root(f, guess, factor, swap_ab ? true : false, tol, max_iter, pol); + if(max_iter >= policies::get_max_root_iterations()) + policies::raise_evaluation_error("boost::math::ibeta_invab_imp<%1%>(%1%,%1%,%1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol); + return (r.first + r.second) / 2; +} + +} // namespace detail + +template +typename tools::promote_args::type + ibeta_inva(RT1 b, RT2 x, RT3 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(p == 0) + { + return tools::max_value(); + } + if(p == 1) + { + return tools::min_value(); + } + + return policies::checked_narrowing_cast( + detail::ibeta_inv_ab_imp( + static_cast(b), + static_cast(x), + static_cast(p), + 1 - static_cast(p), + false, pol), + "boost::math::ibeta_inva<%1%>(%1%,%1%,%1%)"); +} + +template +typename tools::promote_args::type + ibetac_inva(RT1 b, RT2 x, RT3 q, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(q == 1) + { + return tools::max_value(); + } + if(q == 0) + { + return tools::min_value(); + } + + return policies::checked_narrowing_cast( + detail::ibeta_inv_ab_imp( + static_cast(b), + static_cast(x), + 1 - static_cast(q), + static_cast(q), + false, pol), + "boost::math::ibetac_inva<%1%>(%1%,%1%,%1%)"); +} + +template +typename tools::promote_args::type + ibeta_invb(RT1 a, RT2 x, RT3 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(p == 0) + { + return tools::min_value(); + } + if(p == 1) + { + return tools::max_value(); + } + + return policies::checked_narrowing_cast( + detail::ibeta_inv_ab_imp( + static_cast(a), + static_cast(x), + static_cast(p), + 1 - static_cast(p), + true, pol), + "boost::math::ibeta_invb<%1%>(%1%,%1%,%1%)"); +} + +template +typename tools::promote_args::type + ibetac_invb(RT1 a, RT2 x, RT3 q, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(q == 1) + { + return tools::min_value(); + } + if(q == 0) + { + return tools::max_value(); + } + + return policies::checked_narrowing_cast( + detail::ibeta_inv_ab_imp( + static_cast(a), + static_cast(x), + 1 - static_cast(q), + static_cast(q), + true, pol), + "boost::math::ibetac_invb<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ibeta_inva(RT1 b, RT2 x, RT3 p) +{ + return boost::math::ibeta_inva(b, x, p, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibetac_inva(RT1 b, RT2 x, RT3 q) +{ + return boost::math::ibetac_inva(b, x, q, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibeta_invb(RT1 a, RT2 x, RT3 p) +{ + return boost::math::ibeta_invb(a, x, p, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibetac_invb(RT1 a, RT2 x, RT3 q) +{ + return boost::math::ibetac_invb(a, x, q, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SP_DETAIL_BETA_INV_AB + + diff --git a/include/boost/math/special_functions/detail/ibeta_inverse.hpp b/include/boost/math/special_functions/detail/ibeta_inverse.hpp new file mode 100644 index 000000000..bf1fe189f --- /dev/null +++ b/include/boost/math/special_functions/detail/ibeta_inverse.hpp @@ -0,0 +1,934 @@ +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2007 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP +#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP + +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +// +// Helper object used by root finding +// code to convert eta to x. +// +template +struct temme_root_finder +{ + temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {} + + std::tr1::tuple operator()(T x) + { + BOOST_MATH_STD_USING // ADL of std names + + T y = 1 - x; + if(y == 0) + { + T big = tools::max_value() / 4; + return std::tr1::make_tuple(-big, -big); + } + if(x == 0) + { + T big = tools::max_value() / 4; + return std::tr1::make_tuple(-big, big); + } + T f = log(x) + a * log(y) + t; + T f1 = (1 / x) - (a / (y)); + return std::tr1::make_tuple(f, f1); + } +private: + T t, a; +}; +// +// See: +// "Asymptotic Inversion of the Incomplete Beta Function" +// N.M. Temme +// Journal of Computation and Applied Mathematics 41 (1992) 145-157. +// Section 2. +// +template +T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + + const T r2 = sqrt(T(2)); + // + // get the first approximation for eta from the inverse + // error function (Eq: 2.9 and 2.10). + // + T eta0 = boost::math::erfc_inv(2 * z, pol); + eta0 /= -sqrt(a / 2); + + T terms[4] = { eta0 }; + T workspace[7]; + // + // calculate powers: + // + T B = b - a; + T B_2 = B * B; + T B_3 = B_2 * B; + // + // Calculate correction terms: + // + + // See eq following 2.15: + workspace[0] = -B * r2 / 2; + workspace[1] = (1 - 2 * B) / 8; + workspace[2] = -(B * r2 / 48); + workspace[3] = T(-1) / 192; + workspace[4] = -B * r2 / 3840; + terms[1] = tools::evaluate_polynomial(workspace, eta0, 5); + // Eq Following 2.17: + workspace[0] = B * r2 * (3 * B - 2) / 12; + workspace[1] = (20 * B_2 - 12 * B + 1) / 128; + workspace[2] = B * r2 * (20 * B - 1) / 960; + workspace[3] = (16 * B_2 + 30 * B - 15) / 4608; + workspace[4] = B * r2 * (21 * B + 32) / 53760; + workspace[5] = (-32 * B_2 + 63) / 368640; + workspace[6] = -B * r2 * (120 * B + 17) / 25804480; + terms[2] = tools::evaluate_polynomial(workspace, eta0, 7); + // Eq Following 2.17: + workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480; + workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216; + workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760; + workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640; + terms[3] = tools::evaluate_polynomial(workspace, eta0, 4); + // + // Bring them together to get a final estimate for eta: + // + T eta = tools::evaluate_polynomial(terms, 1/a, 4); + // + // now we need to convert eta to x, by solving the appropriate + // quadratic equation: + // + T eta_2 = eta * eta; + T c = -exp(-eta_2 / 2); + T x; + if(eta_2 == 0) + x = 0.5; + else + x = (1 + eta * sqrt((1 + c) / eta_2)) / 2; + + BOOST_ASSERT(x >= 0); + BOOST_ASSERT(x <= 1); + BOOST_ASSERT(eta * (x - 0.5) >= 0); +#ifdef BOOST_INSTRUMENT + std::cout << "Estimating x with Temme method 1: " << x << std::endl; +#endif + return x; +} +// +// See: +// "Asymptotic Inversion of the Incomplete Beta Function" +// N.M. Temme +// Journal of Computation and Applied Mathematics 41 (1992) 145-157. +// Section 3. +// +template +T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + + // + // Get first estimate for eta, see Eq 3.9 and 3.10, + // but note there is a typo in Eq 3.10: + // + T eta0 = boost::math::erfc_inv(2 * z, pol); + eta0 /= -sqrt(r / 2); + + T s = sin(theta); + T c = cos(theta); + // + // Now we need to purturb eta0 to get eta, which we do by + // evaluating the polynomial in 1/r at the bottom of page 151, + // to do this we first need the error terms e1, e2 e3 + // which we'll fill into the array "terms". Since these + // terms are themselves polynomials, we'll need another + // array "workspace" to calculate those... + // + T terms[4] = { eta0 }; + T workspace[6]; + // + // some powers of sin(theta)cos(theta) that we'll need later: + // + T sc = s * c; + T sc_2 = sc * sc; + T sc_3 = sc_2 * sc; + T sc_4 = sc_2 * sc_2; + T sc_5 = sc_2 * sc_3; + T sc_6 = sc_3 * sc_3; + T sc_7 = sc_4 * sc_3; + // + // Calculate e1 and put it in terms[1], see the middle of page 151: + // + workspace[0] = (2 * s * s - 1) / (3 * s * c); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 }; + workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 }; + workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 }; + workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 }; + workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5); + terms[1] = tools::evaluate_polynomial(workspace, eta0, 5); + // + // Now evaluate e2 and put it in terms[2]: + // + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 }; + workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 }; + workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 }; + workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 }; + workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6); + terms[2] = tools::evaluate_polynomial(workspace, eta0, 4); + // + // And e3, and put it in terms[3]: + // + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 }; + workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 }; + workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 }; + workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7); + terms[3] = tools::evaluate_polynomial(workspace, eta0, 3); + // + // Bring the correction terms together to evaluate eta, + // this is the last equation on page 151: + // + T eta = tools::evaluate_polynomial(terms, 1/r, 4); + // + // Now that we have eta we need to back solve for x, + // we seek the value of x that gives eta in Eq 3.2. + // The two methods used are described in section 5. + // + // Begin by defining a few variables we'll need later: + // + T x; + T s_2 = s * s; + T c_2 = c * c; + T alpha = c / s; + alpha *= alpha; + T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2); + // + // Temme doesn't specify what value to switch on here, + // but this seems to work pretty well: + // + if(fabs(eta) < 0.7) + { + // + // Small eta use the expansion Temme gives in the second equation + // of section 5, it's a polynomial in eta: + // + workspace[0] = s * s; + workspace[1] = s * c; + workspace[2] = (1 - 2 * workspace[0]) / 3; + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 1, -13, 13 }; + workspace[3] = tools::evaluate_polynomial(co3, workspace[0], 3) / (36 * s * c); + static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 1, 21, -69, 46 }; + workspace[4] = tools::evaluate_polynomial(co4, workspace[0], 4) / (270 * workspace[0] * c * c); + x = tools::evaluate_polynomial(workspace, eta, 5); +#ifdef BOOST_INSTRUMENT + std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl; +#endif + } + else + { + // + // If eta is large we need to solve Eq 3.2 more directly, + // begin by getting an initial approximation for x from + // the last equation on page 155, this is a polynomial in u: + // + T u = exp(lu); + workspace[0] = u; + workspace[1] = alpha; + workspace[2] = 0; + workspace[3] = 3 * alpha * (3 * alpha + 1) / 6; + workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24; + workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120; + x = tools::evaluate_polynomial(workspace, u, 6); + // + // At this point we may or may not have the right answer, Eq-3.2 has + // two solutions for x for any given eta, however the mapping in 3.2 + // is 1:1 with the sign of eta and x-sin^2(theta) being the same. + // So we can check if we have the right root of 3.2, and if not + // switch x for 1-x. This transformation is motivated by the fact + // that the distribution is *almost* symetric so 1-x will be in the right + // ball park for the solution: + // + if((x - s_2) * eta < 0) + x = 1 - x; +#ifdef BOOST_INSTRUMENT + std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl; +#endif + } + // + // The final step is a few Newton-Raphson iterations to + // clean up our approximation for x, this is pretty cheap + // in general, and very cheap compared to an incomplete beta + // evaluation. The limits set on x come from the observation + // that the sign of eta and x-sin^2(theta) are the same. + // + T lower, upper; + if(eta < 0) + { + lower = 0; + upper = s_2; + } + else + { + lower = s_2; + upper = 1; + } + // + // If our initial approximation is out of bounds then bisect: + // + if((x < lower) || (x > upper)) + x = (lower+upper) / 2; + // + // And iterate: + // + x = tools::newton_raphson_iterate( + temme_root_finder(-lu, alpha), x, lower, upper, policies::digits() / 2); + + return x; +} +// +// See: +// "Asymptotic Inversion of the Incomplete Beta Function" +// N.M. Temme +// Journal of Computation and Applied Mathematics 41 (1992) 145-157. +// Section 4. +// +template +T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + + // + // Begin by getting an initial approximation for the quantity + // eta from the dominant part of the incomplete beta: + // + T eta0; + if(p < q) + eta0 = boost::math::gamma_q_inv(b, p, pol); + else + eta0 = boost::math::gamma_p_inv(b, q, pol); + eta0 /= a; + // + // Define the variables and powers we'll need later on: + // + T mu = b / a; + T w = sqrt(1 + mu); + T w_2 = w * w; + T w_3 = w_2 * w; + T w_4 = w_2 * w_2; + T w_5 = w_3 * w_2; + T w_6 = w_3 * w_3; + T w_7 = w_4 * w_3; + T w_8 = w_4 * w_4; + T w_9 = w_5 * w_4; + T w_10 = w_5 * w_5; + T d = eta0 - mu; + T d_2 = d * d; + T d_3 = d_2 * d; + T d_4 = d_2 * d_2; + T w1 = w + 1; + T w1_2 = w1 * w1; + T w1_3 = w1 * w1_2; + T w1_4 = w1_2 * w1_2; + // + // Now we need to compute the purturbation error terms that + // convert eta0 to eta, these are all polynomials of polynomials. + // Probably these should be re-written to use tabulated data + // (see examples above), but it's less of a win in this case as we + // need to calculate the individual powers for the denominator terms + // anyway, so we might as well use them for the numerator-polynomials + // as well.... + // + // Refer to p154-p155 for the details of these expansions: + // + T e1 = (w + 2) * (w - 1) / (3 * w); + e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1); + e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3); + e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4); + e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5); + + T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3); + e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4); + e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3); + e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (14696640 * w1_4 * w_6); + + T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2); + e3 -= (442043 * w_9 + 2054169 * w_8 + 3803094 * w_7 + 3470754 * w_6 + 2141568 * w_5 - 2393568 * w_4 - 19904934 * w_3 - 34714674 * w_2 - 23128299 * w - 5253353) * d / (146966400 * w_6 * w1_3); + e3 -= (116932 * w_10 + 819281 * w_9 + 2378172 * w_8 + 4341330 * w_7 + 6806004 * w_6 + 10622748 * w_5 + 18739500 * w_4 + 30651894 * w_3 + 30869976 * w_2 + 15431867 * w + 2919016) * d_2 / (146966400 * w1_4 * w_7); + // + // Combine eta0 and the error terms to compute eta (Second eqaution p155): + // + T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a); + // + // Now we need to solve Eq 4.2 to obtain x. For any given value of + // eta there are two solutions to this equation, and since the distribtion + // may be very skewed, these are not related by x ~ 1-x we used when + // implementing section 3 above. However we know that: + // + // cross < x <= 1 ; iff eta < mu + // x == cross ; iff eta == mu + // 0 <= x < cross ; iff eta > mu + // + // Where cross == 1 / (1 + mu) + // Many thanks to Prof Temme for clarifying this point. + // + // Therefore we'll just jump straight into Newton iterations + // to solve Eq 4.2 using these bounds, and simple bisection + // as the first guess, in practice this converges pretty quickly + // and we only need a few digits correct anyway: + // + if(eta <= 0) + eta = tools::min_value(); + T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu; + T cross = 1 / (1 + mu); + T lower = eta < mu ? cross : 0; + T upper = eta < mu ? 1 : cross; + T x = (lower + upper) / 2; + x = tools::newton_raphson_iterate( + temme_root_finder(u, mu), x, lower, upper, policies::digits() / 2); +#ifdef BOOST_INSTRUMENT + std::cout << "Estimating x with Temme method 3: " << x << std::endl; +#endif + return x; +} + +template +struct ibeta_roots +{ + ibeta_roots(T _a, T _b, T t, bool inv = false) + : a(_a), b(_b), target(t), invert(inv) {} + + std::tr1::tuple operator()(T x) + { + BOOST_MATH_STD_USING // ADL of std names + + BOOST_FPU_EXCEPTION_GUARD + + T f1; + T y = 1 - x; + T f = ibeta_imp(a, b, x, Policy(), invert, true, &f1) - target; + if(invert) + f1 = -f1; + if(y == 0) + y = tools::min_value() * 64; + if(x == 0) + x = tools::min_value() * 64; + + T f2 = f1 * (-y * a + (b - 2) * x + 1); + if(fabs(f2) < y * x * tools::max_value()) + f2 /= (y * x); + if(invert) + f2 = -f2; + + // make sure we don't have a zero derivative: + if(f1 == 0) + f1 = (invert ? -1 : 1) * tools::min_value() * 64; + + return std::tr1::make_tuple(f, f1, f2); + } +private: + T a, b, target; + bool invert; +}; + +template +T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py) +{ + BOOST_MATH_STD_USING // For ADL of math functions. + + // + // The flag invert is set to true if we swap a for b and p for q, + // in which case the result has to be subtracted from 1: + // + bool invert = false; + // + // Depending upon which approximation method we use, we may end up + // calculating either x or y initially (where y = 1-x): + // + T x = 0; // Set to a safe zero to avoid a + // MSVC 2005 warning C4701: potentially uninitialized local variable 'x' used + // But code inspection appears to ensure that x IS assigned whatever the code path. + T y; + + // For some of the methods we can put tighter bounds + // on the result than simply [0,1]: + // + T lower = 0; + T upper = 1; + // + // Student's T with b = 0.5 gets handled as a special case, swap + // around if the arguments are in the "wrong" order: + // + if(a == 0.5f) + { + std::swap(a, b); + std::swap(p, q); + invert = !invert; + } + // + // Handle trivial cases first: + // + if(q == 0) + { + if(py) *py = 0; + return 1; + } + else if(p == 0) + { + if(py) *py = 1; + return 0; + } + else if((a == 1) && (b == 1)) + { + if(py) *py = 1 - p; + return p; + } + else if((b == 0.5f) && (a >= 0.5f)) + { + // + // We have a Student's T distribution: + x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol); + } + else if(a + b > 5) + { + // + // When a+b is large then we can use one of Prof Temme's + // asymptotic expansions, begin by swapping things around + // so that p < 0.5, we do this to avoid cancellations errors + // when p is large. + // + if(p > 0.5) + { + std::swap(a, b); + std::swap(p, q); + invert = !invert; + } + T minv = (std::min)(a, b); + T maxv = (std::max)(a, b); + if((sqrt(minv) > (maxv - minv)) && (minv > 5)) + { + // + // When a and b differ by a small amount + // the curve is quite symmetrical and we can use an error + // function to approximate the inverse. This is the cheapest + // of the three Temme expantions, and the calculated value + // for x will never be much larger than p, so we don't have + // to worry about cancellation as long as p is small. + // + x = temme_method_1_ibeta_inverse(a, b, p, pol); + y = 1 - x; + } + else + { + T r = a + b; + T theta = asin(sqrt(a / r)); + T lambda = minv / r; + if((lambda >= 0.2) && (lambda <= 0.8) && (lambda >= 10)) + { + // + // The second error function case is the next cheapest + // to use, it brakes down when the result is likely to be + // very small, if a+b is also small, but we can use a + // cheaper expansion there in any case. As before x won't + // be much larger than p, so as long as p is small we should + // be free of cancellation error. + // + T ppa = pow(p, 1/a); + if((ppa < 0.0025) && (a + b < 200)) + { + x = ppa * pow(a * boost::math::beta(a, b, pol), 1/a); + } + else + x = temme_method_2_ibeta_inverse(a, b, p, r, theta, pol); + y = 1 - x; + } + else + { + // + // If we get here then a and b are very different in magnitude + // and we need to use the third of Temme's methods which + // involves inverting the incomplete gamma. This is much more + // expensive than the other methods. We also can only use this + // method when a > b, which can lead to cancellation errors + // if we really want y (as we will when x is close to 1), so + // a different expansion is used in that case. + // + if(a < b) + { + std::swap(a, b); + std::swap(p, q); + invert = !invert; + } + // + // Try and compute the easy way first: + // + T bet = 0; + if(b < 2) + bet = boost::math::beta(a, b, pol); + if(bet != 0) + { + y = pow(b * q * bet, 1/b); + x = 1 - y; + } + else + y = 1; + if(y > 1e-5) + { + x = temme_method_3_ibeta_inverse(a, b, p, q, pol); + y = 1 - x; + } + } + } + } + else if((a < 1) && (b < 1)) + { + // + // Both a and b less than 1, + // there is a point of inflection at xs: + // + T xs = (1 - a) / (2 - a - b); + // + // Now we need to ensure that we start our iteration from the + // right side of the inflection point: + // + T fs = boost::math::ibeta(a, b, xs, pol) - p; + if(fabs(fs) / p < tools::epsilon() * 3) + { + // The result is at the point of inflection, best just return it: + *py = invert ? xs : 1 - xs; + return invert ? 1-xs : xs; + } + if(fs < 0) + { + std::swap(a, b); + std::swap(p, q); + invert = true; + xs = 1 - xs; + } + T xg = pow(a * p * boost::math::beta(a, b, pol), 1/a); + x = xg / (1 + xg); + y = 1 / (1 + xg); + // + // And finally we know that our result is below the inflection + // point, so set an upper limit on our search: + // + if(x > xs) + x = xs; + upper = xs; + } + else if((a > 1) && (b > 1)) + { + // + // Small a and b, both greater than 1, + // there is a point of inflection at xs, + // and it's complement is xs2, we must always + // start our iteration from the right side of the + // point of inflection. + // + T xs = (a - 1) / (a + b - 2); + T xs2 = (b - 1) / (a + b - 2); + T ps = boost::math::ibeta(a, b, xs, pol) - p; + + if(ps < 0) + { + std::swap(a, b); + std::swap(p, q); + std::swap(xs, xs2); + invert = true; + } + // + // Estimate x and y, using expm1 to get a good estimate + // for y when it's very small: + // + T lx = log(p * a * boost::math::beta(a, b, pol)) / a; + x = exp(lx); + y = x < 0.9 ? 1 - x : -boost::math::expm1(lx, pol); + + if((b < a) && (x < 0.2)) + { + // + // Under a limited range of circumstances we can improve + // our estimate for x, frankly it's clear if this has much effect! + // + T ap1 = a - 1; + T bm1 = b - 1; + T a_2 = a * a; + T a_3 = a * a_2; + T b_2 = b * b; + T terms[5] = { 0, 1 }; + terms[2] = bm1 / ap1; + ap1 *= ap1; + terms[3] = bm1 * (3 * a * b + 5 * b + a_2 - a - 4) / (2 * (a + 2) * ap1); + ap1 *= (a + 1); + terms[4] = bm1 * (33 * a * b_2 + 31 * b_2 + 8 * a_2 * b_2 - 30 * a * b - 47 * b + 11 * a_2 * b + 6 * a_3 * b + 18 + 4 * a - a_3 + a_2 * a_2 - 10 * a_2) + / (3 * (a + 3) * (a + 2) * ap1); + x = tools::evaluate_polynomial(terms, x, 5); + } + // + // And finally we know that our result is below the inflection + // point, so set an upper limit on our search: + // + if(x > xs) + x = xs; + upper = xs; + } + else /*if((a <= 1) != (b <= 1))*/ + { + // + // If all else fails we get here, only one of a and b + // is above 1, and a+b is small. Start by swapping + // things around so that we have a concave curve with b > a + // and no points of inflection in [0,1]. As long as we expect + // x to be small then we can use the simple (and cheap) power + // term to estimate x, but when we expect x to be large then + // this greatly underestimates x and leaves us trying to + // iterate "round the corner" which may take almost forever... + // + // We could use Temme's inverse gamma function case in that case, + // this works really rather well (albeit expensively) even though + // strictly speaking we're outside it's defined range. + // + // However it's expensive to compute, and an alternative approach + // which models the curve as a distorted quarter circle is much + // cheaper to compute, and still keeps the number of iterations + // required down to a reasonable level. With thanks to Prof Temme + // for this suggestion. + // + if(b < a) + { + std::swap(a, b); + std::swap(p, q); + invert = true; + } + if(pow(p, 1/a) < 0.5) + { + x = pow(p * a * boost::math::beta(a, b, pol), 1 / a); + if(x == 0) + x = boost::math::tools::min_value(); + y = 1 - x; + } + else /*if(pow(q, 1/b) < 0.1)*/ + { + // model a distorted quarter circle: + y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b); + if(y == 0) + y = boost::math::tools::min_value(); + x = 1 - y; + } + } + + // + // Now we have a guess for x (and for y) we can set things up for + // iteration. If x > 0.5 it pays to swap things round: + // + if(x > 0.5) + { + std::swap(a, b); + std::swap(p, q); + std::swap(x, y); + invert = !invert; + T l = 1 - upper; + T u = 1 - lower; + lower = l; + upper = u; + } + // + // lower bound for our search: + // + // We're not interested in denormalised answers as these tend to + // these tend to take up lots of iterations, given that we can't get + // accurate derivatives in this area (they tend to be infinite). + // + if(lower == 0) + { + if(invert && (py == 0)) + { + // + // We're not interested in answers smaller than machine epsilon: + // + lower = boost::math::tools::epsilon(); + if(x < lower) + x = lower; + } + else + lower = boost::math::tools::min_value(); + if(x < lower) + x = lower; + } + // + // Figure out how many digits to iterate towards: + // + int digits = boost::math::policies::digits() / 2; + if((x < 1e-50) && ((a < 1) || (b < 1))) + { + // + // If we're in a region where the first derivative is very + // large, then we have to take care that the root-finder + // doesn't terminate prematurely. We'll bump the precision + // up to avoid this, but we have to take care not to set the + // precision too high or the last few iterations will just + // thrash around and convergence may be slow in this case. + // Try 3/4 of machine epsilon: + // + digits *= 3; + digits /= 2; + } + // + // Now iterate, we can use either p or q as the target here + // depending on which is smaller: + // + x = boost::math::tools::halley_iterate( + boost::math::detail::ibeta_roots(a, b, (p < q ? p : q), (p < q ? false : true)), x, lower, upper, digits); + // + // We don't really want these asserts here, but they are useful for sanity + // checking that we have the limits right, uncomment if you suspect bugs *only*. + // + //BOOST_ASSERT(x != upper); + //BOOST_ASSERT((x != lower) || (x == boost::math::tools::min_value()) || (x == boost::math::tools::epsilon())); + // + // Tidy up, if we "lower" was too high then zero is the best answer we have: + // + if(x == lower) + x = 0; + if(py) + *py = invert ? x : 1 - x; + return invert ? 1-x : x; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol) +{ + static const char* function = "boost::math::ibeta_inv<%1%>(%1%,%1%,%1%)"; + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(a <= 0) + return policies::raise_domain_error(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + return policies::raise_domain_error(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol); + if((p < 0) || (p > 1)) + return policies::raise_domain_error(function, "Argument p outside the range [0,1] in the incomplete beta function inverse (got p=%1%).", p, pol); + + value_type rx, ry; + + rx = detail::ibeta_inv_imp( + static_cast(a), + static_cast(b), + static_cast(p), + static_cast(1 - p), + forwarding_policy(), &ry); + + if(py) *py = policies::checked_narrowing_cast(ry, function); + return policies::checked_narrowing_cast(rx, function); +} + +template +inline typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p, T4* py) +{ + return ibeta_inv(a, b, p, py, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p) +{ + return ibeta_inv(a, b, p, static_cast(0), policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p, const Policy& pol) +{ + return ibeta_inv(a, b, p, static_cast(0), pol); +} + +template +inline typename tools::promote_args::type + ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol) +{ + static const char* function = "boost::math::ibetac_inv<%1%>(%1%,%1%,%1%)"; + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + if(a <= 0) + policies::raise_domain_error(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol); + if(b <= 0) + policies::raise_domain_error(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol); + if((q < 0) || (q > 1)) + policies::raise_domain_error(function, "Argument q outside the range [0,1] in the incomplete beta function inverse (got q=%1%).", q, pol); + + value_type rx, ry; + + rx = detail::ibeta_inv_imp( + static_cast(a), + static_cast(b), + static_cast(1 - q), + static_cast(q), + forwarding_policy(), &ry); + + if(py) *py = policies::checked_narrowing_cast(ry, function); + return policies::checked_narrowing_cast(rx, function); +} + +template +inline typename tools::promote_args::type + ibetac_inv(T1 a, T2 b, T3 q, T4* py) +{ + return ibetac_inv(a, b, q, py, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibetac_inv(RT1 a, RT2 b, RT3 q) +{ + typedef typename remove_cv::type dummy; + return ibetac_inv(a, b, q, static_cast(0), policies::policy<>()); +} + +template +inline typename tools::promote_args::type + ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy& pol) +{ + typedef typename remove_cv::type dummy; + return ibetac_inv(a, b, q, static_cast(0), pol); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP + + + diff --git a/include/boost/math/special_functions/detail/igamma_inverse.hpp b/include/boost/math/special_functions/detail/igamma_inverse.hpp new file mode 100644 index 000000000..8fd564faa --- /dev/null +++ b/include/boost/math/special_functions/detail/igamma_inverse.hpp @@ -0,0 +1,466 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP +#define BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ + +namespace detail{ + +template +T find_inverse_s(T p, T q) +{ + // + // Computation of the Incomplete Gamma Function Ratios and their Inverse + // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR. + // ACM Transactions on Mathematical Software, Vol. 12, No. 4, + // December 1986, Pages 377-393. + // + // See equation 32. + // + BOOST_MATH_STD_USING + T t; + if(p < 0.5) + { + t = sqrt(-2 * log(p)); + } + else + { + t = sqrt(-2 * log(q)); + } + static const double a[4] = { 3.31125922108741, 11.6616720288968, 4.28342155967104, 0.213623493715853 }; + static const double b[5] = { 1, 6.61053765625462, 6.40691597760039, 1.27364489782223, 0.3611708101884203e-1 }; + T s = t - tools::evaluate_polynomial(a, t) / tools::evaluate_polynomial(b, t); + if(p < 0.5) + s = -s; + return s; +} + +template +T didonato_SN(T a, T x, unsigned N, T tolerance = 0) +{ + // + // Computation of the Incomplete Gamma Function Ratios and their Inverse + // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR. + // ACM Transactions on Mathematical Software, Vol. 12, No. 4, + // December 1986, Pages 377-393. + // + // See equation 34. + // + T sum = 1; + if(N >= 1) + { + T partial = x / (a + 1); + sum += partial; + for(unsigned i = 2; i <= N; ++i) + { + partial *= x / (a + i); + sum += partial; + if(partial < tolerance) + break; + } + } + return sum; +} + +template +inline T didonato_FN(T p, T a, T x, unsigned N, T tolerance, const Policy& pol) +{ + // + // Computation of the Incomplete Gamma Function Ratios and their Inverse + // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR. + // ACM Transactions on Mathematical Software, Vol. 12, No. 4, + // December 1986, Pages 377-393. + // + // See equation 34. + // + BOOST_MATH_STD_USING + T u = log(p) + boost::math::lgamma(a + 1, pol); + return exp((u + x - log(didonato_SN(a, x, N, tolerance))) / a); +} + +template +T find_inverse_gamma(T a, T p, T q, const Policy& pol) +{ + // + // In order to understand what's going on here, you will + // need to refer to: + // + // Computation of the Incomplete Gamma Function Ratios and their Inverse + // ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR. + // ACM Transactions on Mathematical Software, Vol. 12, No. 4, + // December 1986, Pages 377-393. + // + BOOST_MATH_STD_USING + + T result; + + if(a == 1) + result = -log(q); + else if(a < 1) + { + T g = boost::math::tgamma(a, pol); + T b = q * g; + if((b > 0.6) || ((b >= 0.45) && (a >= 0.3))) + { + // DiDonato & Morris Eq 21: + // + // There is a slight variation from DiDonato and Morris here: + // the first form given here is unstable when p is close to 1, + // making it impossible to compute the inverse of Q(a,x) for small + // q. Fortunately the second form works perfectly well in this case. + // + T u; + if((b * q > 1e-8) && (q > 1e-5)) + { + u = pow(p * g * a, 1 / a); + } + else + { + u = exp((-q / a) - constants::euler()); + } + result = u / (1 - (u / (a + 1))); + } + else if((a < 0.3) && (b >= 0.35)) + { + // DiDonato & Morris Eq 22: + T t = exp(-constants::euler() - b); + T u = t * exp(t); + result = t * exp(u); + } + else if((b > 0.15) || (a >= 0.3)) + { + // DiDonato & Morris Eq 23: + T y = -log(b); + T u = y - (1 - a) * log(y); + result = y - (1 - a) * log(u) - log(1 + (1 - a) / (1 + u)); + } + else if (b > 0.1) + { + // DiDonato & Morris Eq 24: + T y = -log(b); + T u = y - (1 - a) * log(y); + result = y - (1 - a) * log(u) - log((u * u + 2 * (3 - a) * u + (2 - a) * (3 - a)) / (u * u + (5 - a) * u + 2)); + } + else + { + // DiDonato & Morris Eq 25: + T y = -log(b); + T c1 = (a - 1) * log(y); + T c1_2 = c1 * c1; + T c1_3 = c1_2 * c1; + T c1_4 = c1_2 * c1_2; + T a_2 = a * a; + T a_3 = a_2 * a; + + T c2 = (a - 1) * (1 + c1); + T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2); + T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6); + T c5 = (a - 1) * (-(c1_4 / 4) + + (11 * a - 17) * c1_3 / 6 + + (-3 * a_2 + 13 * a -13) * c1_2 + + (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2 + + (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12); + + T y_2 = y * y; + T y_3 = y_2 * y; + T y_4 = y_2 * y_2; + result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4); + } + } + else + { + // DiDonato and Morris Eq 31: + T s = find_inverse_s(p, q); + + T s_2 = s * s; + T s_3 = s_2 * s; + T s_4 = s_2 * s_2; + T s_5 = s_4 * s; + T ra = sqrt(a); + + T w = a + s * ra + (s * s -1) / 3; + w += (s_3 - 7 * s) / (36 * ra); + w -= (3 * s_4 + 7 * s_2 - 16) / (810 * a); + w += (9 * s_5 + 256 * s_3 - 433 * s) / (38880 * a * ra); + + if((a >= 500) && (fabs(1 - w / a) < 1e-6)) + { + result = w; + } + else if (p > 0.5) + { + if(w < 3 * a) + { + result = w; + } + else + { + T D = (std::max)(T(2), a * (a - 1)); + T lg = boost::math::lgamma(a, pol); + T lb = log(q) + lg; + if(lb < -D * 2.3) + { + // DiDonato and Morris Eq 25: + T y = -lb; + T c1 = (a - 1) * log(y); + T c1_2 = c1 * c1; + T c1_3 = c1_2 * c1; + T c1_4 = c1_2 * c1_2; + T a_2 = a * a; + T a_3 = a_2 * a; + + T c2 = (a - 1) * (1 + c1); + T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2); + T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6); + T c5 = (a - 1) * (-(c1_4 / 4) + + (11 * a - 17) * c1_3 / 6 + + (-3 * a_2 + 13 * a -13) * c1_2 + + (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2 + + (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12); + + T y_2 = y * y; + T y_3 = y_2 * y; + T y_4 = y_2 * y_2; + result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4); + } + else + { + // DiDonato and Morris Eq 33: + T u = -lb + (a - 1) * log(w) - log(1 + (1 - a) / (1 + w)); + result = -lb + (a - 1) * log(u) - log(1 + (1 - a) / (1 + u)); + } + } + } + else + { + // DiDonato and Morris Eq 35: + T z = didonato_FN(p, a, w, 0, T(0), pol); + z = didonato_FN(p, a, z, 2, T(0), pol); + z = didonato_FN(p, a, z, 2, T(0), pol); + z = didonato_FN(p, a, z, 3, T(0), pol); + + if((z <= 0.01 * (a + 1)) || (z > 0.7 * (a + 1))) + { + result = z; + } + else + { + // DiDonato and Morris Eq 36: + T zb = didonato_FN(p, a, z, 100, T(1e-4), pol); + T u = log(p) + boost::math::lgamma(a + 1, pol); + result = zb * (1 - (a * log(zb) - zb - u + log(didonato_SN(a, z, 100, T(1e-4)))) / (a - zb)); + } + } + } + return result; +} + +template +struct gamma_p_inverse_func +{ + gamma_p_inverse_func(T a_, T p_, bool inv) : a(a_), p(p_), invert(inv) + { + // + // If p is too near 1 then P(x) - p suffers from cancellation + // errors causing our root-finding algorithms to "thrash", better + // to invert in this case and calculate Q(x) - (1-p) instead. + // + // Of course if p is *very* close to 1, then the answer we get will + // be inaccurate anyway (because there's not enough information in p) + // but at least we will converge on the (inaccurate) answer quickly. + // + if(p > 0.9) + { + p = 1 - p; + invert = !invert; + } + } + + std::tr1::tuple operator()(const T& x)const + { + BOOST_FPU_EXCEPTION_GUARD + // + // Calculate P(x) - p and the first two derivates, or if the invert + // flag is set, then Q(x) - q and it's derivatives. + // + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + BOOST_MATH_STD_USING // For ADL of std functions. + + T f, f1; + value_type ft; + f = static_cast(boost::math::detail::gamma_incomplete_imp( + static_cast(a), + static_cast(x), + true, invert, + forwarding_policy(), &ft)); + f1 = static_cast(ft); + T f2; + T div = (a - x - 1) / x; + f2 = f1; + if((fabs(div) > 1) && (tools::max_value() / fabs(div) < f2)) + { + // overflow: + f2 = -tools::max_value() / 2; + } + else + { + f2 *= div; + } + + if(invert) + { + f1 = -f1; + f2 = -f2; + } + + return std::tr1::make_tuple(f - p, f1, f2); + } +private: + T a, p; + bool invert; +}; + +template +T gamma_p_inv_imp(T a, T p, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std functions. + + static const char* function = "boost::math::gamma_p_inv<%1%>(%1%, %1%)"; + + if(a <= 0) + policies::raise_domain_error(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol); + if((p < 0) || (p > 1)) + policies::raise_domain_error(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got p=%1%).", p, pol); + if(p == 1) + return tools::max_value(); + if(p == 0) + return 0; + T guess = detail::find_inverse_gamma(a, p, 1 - p, pol); + T lower = tools::min_value(); + if(guess <= lower) + guess = tools::min_value(); + // + // Work out how many digits to converge to, normally this is + // 2/3 of the digits in T, but if the first derivative is very + // large convergence is slow, so we'll bump it up to full + // precision to prevent premature termination of the root-finding routine. + // + unsigned digits = (policies::digits() * 2) / 3; + if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon()))) + digits = policies::digits() - 2; + // + // Go ahead and iterate: + // + guess = tools::halley_iterate( + detail::gamma_p_inverse_func(a, p, false), + guess, + lower, + tools::max_value(), + digits); + if(guess == lower) + guess = policies::raise_underflow_error(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol); + return guess; +} + +template +T gamma_q_inv_imp(T a, T q, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std functions. + + static const char* function = "boost::math::gamma_q_inv<%1%>(%1%, %1%)"; + + if(a <= 0) + policies::raise_domain_error(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol); + if((q < 0) || (q > 1)) + policies::raise_domain_error(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got q=%1%).", q, pol); + if(q == 0) + return tools::max_value(); + if(q == 1) + return 0; + T guess = detail::find_inverse_gamma(a, 1 - q, q, pol); + T lower = tools::min_value(); + if(guess <= lower) + guess = tools::min_value(); + // + // Work out how many digits to converge to, normally this is + // 2/3 of the digits in T, but if the first derivative is very + // large convergence is slow, so we'll bump it up to full + // precision to prevent premature termination of the root-finding routine. + // + unsigned digits = (policies::digits() * 2) / 3; + if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon()))) + digits = policies::digits(); + // + // Go ahead and iterate: + // + guess = tools::halley_iterate( + detail::gamma_p_inverse_func(a, q, true), + guess, + lower, + tools::max_value(), + digits); + if(guess == lower) + guess = policies::raise_underflow_error(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol); + return guess; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + gamma_p_inv(T1 a, T2 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::gamma_p_inv_imp( + static_cast(a), + static_cast(p), pol); +} + +template +inline typename tools::promote_args::type + gamma_q_inv(T1 a, T2 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::gamma_q_inv_imp( + static_cast(a), + static_cast(p), pol); +} + +template +inline typename tools::promote_args::type + gamma_p_inv(T1 a, T2 p) +{ + return gamma_p_inv(a, p, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + gamma_q_inv(T1 a, T2 p) +{ + return gamma_q_inv(a, p, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP + + diff --git a/include/boost/math/special_functions/detail/igamma_large.hpp b/include/boost/math/special_functions/detail/igamma_large.hpp new file mode 100644 index 000000000..539489a57 --- /dev/null +++ b/include/boost/math/special_functions/detail/igamma_large.hpp @@ -0,0 +1,764 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file implements the asymptotic expansions of the incomplete +// gamma functions P(a, x) and Q(a, x), used when a is large and +// x ~ a. +// +// The primary reference is: +// +// "The Asymptotic Expansion of the Incomplete Gamma Functions" +// N. M. Temme. +// Siam J. Math Anal. Vol 10 No 4, July 1979, p757. +// +// A different way of evaluating these expansions, +// plus a lot of very useful background information is in: +// +// "A Set of Algorithms For the Incomplete Gamma Functions." +// N. M. Temme. +// Probability in the Engineering and Informational Sciences, +// 8, 1994, 291. +// +// An alternative implementation is in: +// +// "Computation of the Incomplete Gamma Function Ratios and their Inverse." +// A. R. Didonato and A. H. Morris. +// ACM TOMS, Vol 12, No 4, Dec 1986, p377. +// +// There are various versions of the same code below, each accurate +// to a different precision. To understand the code, refer to Didonato +// and Morris, from Eq 17 and 18 onwards. +// +// The coefficients used here are not taken from Didonato and Morris: +// the domain over which these expansions are used is slightly different +// to theirs, and their constants are not quite accurate enough for +// 128-bit long double's. Instead the coefficients were calculated +// using the methods described by Temme p762 from Eq 3.8 onwards. +// The values obtained agree with those obtained by Didonato and Morris +// (at least to the first 30 digits that they provide). +// At double precision the degrees of polynomial required for full +// machine precision are close to those recomended to Didonato and Morris, +// but of course many more terms are needed for larger types. +// +#ifndef BOOST_MATH_DETAIL_IGAMMA_LARGE +#define BOOST_MATH_DETAIL_IGAMMA_LARGE + +namespace boost{ namespace math{ namespace detail{ + +// This version will never be called (at runtime), it's a stub used +// when T is unsuitable to be passed to these routines: +// +template +inline T igamma_temme_large(T, T, const Policy& /* pol */, mpl::int_<0> const *) +{ + // stub function, should never actually be called + BOOST_ASSERT(0); + return 0; +} +// +// This version is accurate for up to 64-bit mantissa's, +// (80-bit long double, or 10^-20). +// +template +T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<64> const *) +{ + BOOST_MATH_STD_USING // ADL of std functions + T sigma = (x - a) / a; + T phi = -boost::math::log1pmx(sigma, pol); + T y = a * phi; + T z = sqrt(2 * phi); + if(x < a) + z = -z; + + T workspace[13]; + + static const T C0[] = { + -0.333333333333333333333L, + 0.0833333333333333333333L, + -0.0148148148148148148148L, + 0.00115740740740740740741L, + 0.000352733686067019400353L, + -0.0001787551440329218107L, + 0.39192631785224377817e-4L, + -0.218544851067999216147e-5L, + -0.18540622107151599607e-5L, + 0.829671134095308600502e-6L, + -0.176659527368260793044e-6L, + 0.670785354340149858037e-8L, + 0.102618097842403080426e-7L, + -0.438203601845335318655e-8L, + 0.914769958223679023418e-9L, + -0.255141939949462497669e-10L, + -0.583077213255042506746e-10L, + 0.243619480206674162437e-10L, + -0.502766928011417558909e-11L, + }; + workspace[0] = tools::evaluate_polynomial(C0, z); + + static const T C1[] = { + -0.00185185185185185185185L, + -0.00347222222222222222222L, + 0.00264550264550264550265L, + -0.000990226337448559670782L, + 0.000205761316872427983539L, + -0.40187757201646090535e-6L, + -0.18098550334489977837e-4L, + 0.764916091608111008464e-5L, + -0.161209008945634460038e-5L, + 0.464712780280743434226e-8L, + 0.137863344691572095931e-6L, + -0.575254560351770496402e-7L, + 0.119516285997781473243e-7L, + -0.175432417197476476238e-10L, + -0.100915437106004126275e-8L, + 0.416279299184258263623e-9L, + -0.856390702649298063807e-10L, + }; + workspace[1] = tools::evaluate_polynomial(C1, z); + + static const T C2[] = { + 0.00413359788359788359788L, + -0.00268132716049382716049L, + 0.000771604938271604938272L, + 0.200938786008230452675e-5L, + -0.000107366532263651605215L, + 0.529234488291201254164e-4L, + -0.127606351886187277134e-4L, + 0.342357873409613807419e-7L, + 0.137219573090629332056e-5L, + -0.629899213838005502291e-6L, + 0.142806142060642417916e-6L, + -0.204770984219908660149e-9L, + -0.140925299108675210533e-7L, + 0.622897408492202203356e-8L, + -0.136704883966171134993e-8L, + }; + workspace[2] = tools::evaluate_polynomial(C2, z); + + static const T C3[] = { + 0.000649434156378600823045L, + 0.000229472093621399176955L, + -0.000469189494395255712128L, + 0.000267720632062838852962L, + -0.756180167188397641073e-4L, + -0.239650511386729665193e-6L, + 0.110826541153473023615e-4L, + -0.56749528269915965675e-5L, + 0.142309007324358839146e-5L, + -0.278610802915281422406e-10L, + -0.169584040919302772899e-6L, + 0.809946490538808236335e-7L, + -0.191111684859736540607e-7L, + }; + workspace[3] = tools::evaluate_polynomial(C3, z); + + static const T C4[] = { + -0.000861888290916711698605L, + 0.000784039221720066627474L, + -0.000299072480303190179733L, + -0.146384525788434181781e-5L, + 0.664149821546512218666e-4L, + -0.396836504717943466443e-4L, + 0.113757269706784190981e-4L, + 0.250749722623753280165e-9L, + -0.169541495365583060147e-5L, + 0.890750753220530968883e-6L, + -0.229293483400080487057e-6L, + }; + workspace[4] = tools::evaluate_polynomial(C4, z); + + static const T C5[] = { + -0.000336798553366358150309L, + -0.697281375836585777429e-4L, + 0.000277275324495939207873L, + -0.000199325705161888477003L, + 0.679778047793720783882e-4L, + 0.141906292064396701483e-6L, + -0.135940481897686932785e-4L, + 0.801847025633420153972e-5L, + -0.229148117650809517038e-5L, + }; + workspace[5] = tools::evaluate_polynomial(C5, z); + + static const T C6[] = { + 0.000531307936463992223166L, + -0.000592166437353693882865L, + 0.000270878209671804482771L, + 0.790235323266032787212e-6L, + -0.815396936756196875093e-4L, + 0.561168275310624965004e-4L, + -0.183291165828433755673e-4L, + -0.307961345060330478256e-8L, + 0.346515536880360908674e-5L, + -0.20291327396058603727e-5L, + 0.57887928631490037089e-6L, + }; + workspace[6] = tools::evaluate_polynomial(C6, z); + + static const T C7[] = { + 0.000344367606892377671254L, + 0.517179090826059219337e-4L, + -0.000334931610811422363117L, + 0.000281269515476323702274L, + -0.000109765822446847310235L, + -0.127410090954844853795e-6L, + 0.277444515115636441571e-4L, + -0.182634888057113326614e-4L, + 0.578769494973505239894e-5L, + }; + workspace[7] = tools::evaluate_polynomial(C7, z); + + static const T C8[] = { + -0.000652623918595309418922L, + 0.000839498720672087279993L, + -0.000438297098541721005061L, + -0.696909145842055197137e-6L, + 0.000166448466420675478374L, + -0.000127835176797692185853L, + 0.462995326369130429061e-4L, + }; + workspace[8] = tools::evaluate_polynomial(C8, z); + + static const T C9[] = { + -0.000596761290192746250124L, + -0.720489541602001055909e-4L, + 0.000678230883766732836162L, + -0.0006401475260262758451L, + 0.000277501076343287044992L, + }; + workspace[9] = tools::evaluate_polynomial(C9, z); + + static const T C10[] = { + 0.00133244544948006563713L, + -0.0019144384985654775265L, + 0.00110893691345966373396L, + }; + workspace[10] = tools::evaluate_polynomial(C10, z); + + static const T C11[] = { + 0.00157972766073083495909L, + 0.000162516262783915816899L, + -0.00206334210355432762645L, + 0.00213896861856890981541L, + -0.00101085593912630031708L, + }; + workspace[11] = tools::evaluate_polynomial(C11, z); + + static const T C12[] = { + -0.00407251211951401664727L, + 0.00640336283380806979482L, + -0.00404101610816766177474L, + }; + workspace[12] = tools::evaluate_polynomial(C12, z); + + T result = tools::evaluate_polynomial(workspace, 1/a); + result *= exp(-y) / sqrt(2 * constants::pi() * a); + if(x < a) + result = -result; + + result += boost::math::erfc(sqrt(y), pol) / 2; + + return result; +} +// +// This one is accurate for 53-bit mantissa's +// (IEEE double precision or 10^-17). +// +template +T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<53> const *) +{ + BOOST_MATH_STD_USING // ADL of std functions + T sigma = (x - a) / a; + T phi = -boost::math::log1pmx(sigma, pol); + T y = a * phi; + T z = sqrt(2 * phi); + if(x < a) + z = -z; + + T workspace[10]; + + static const T C0[] = { + static_cast(-0.33333333333333333L), + static_cast(0.083333333333333333L), + static_cast(-0.014814814814814815L), + static_cast(0.0011574074074074074L), + static_cast(0.0003527336860670194L), + static_cast(-0.00017875514403292181L), + static_cast(0.39192631785224378e-4L), + static_cast(-0.21854485106799922e-5L), + static_cast(-0.185406221071516e-5L), + static_cast(0.8296711340953086e-6L), + static_cast(-0.17665952736826079e-6L), + static_cast(0.67078535434014986e-8L), + static_cast(0.10261809784240308e-7L), + static_cast(-0.43820360184533532e-8L), + static_cast(0.91476995822367902e-9L), + }; + workspace[0] = tools::evaluate_polynomial(C0, z); + + static const T C1[] = { + static_cast(-0.0018518518518518519L), + static_cast(-0.0034722222222222222L), + static_cast(0.0026455026455026455L), + static_cast(-0.00099022633744855967L), + static_cast(0.00020576131687242798L), + static_cast(-0.40187757201646091e-6L), + static_cast(-0.18098550334489978e-4L), + static_cast(0.76491609160811101e-5L), + static_cast(-0.16120900894563446e-5L), + static_cast(0.46471278028074343e-8L), + static_cast(0.1378633446915721e-6L), + static_cast(-0.5752545603517705e-7L), + static_cast(0.11951628599778147e-7L), + }; + workspace[1] = tools::evaluate_polynomial(C1, z); + + static const T C2[] = { + static_cast(0.0041335978835978836L), + static_cast(-0.0026813271604938272L), + static_cast(0.00077160493827160494L), + static_cast(0.20093878600823045e-5L), + static_cast(-0.00010736653226365161L), + static_cast(0.52923448829120125e-4L), + static_cast(-0.12760635188618728e-4L), + static_cast(0.34235787340961381e-7L), + static_cast(0.13721957309062933e-5L), + static_cast(-0.6298992138380055e-6L), + static_cast(0.14280614206064242e-6L), + }; + workspace[2] = tools::evaluate_polynomial(C2, z); + + static const T C3[] = { + static_cast(0.00064943415637860082L), + static_cast(0.00022947209362139918L), + static_cast(-0.00046918949439525571L), + static_cast(0.00026772063206283885L), + static_cast(-0.75618016718839764e-4L), + static_cast(-0.23965051138672967e-6L), + static_cast(0.11082654115347302e-4L), + static_cast(-0.56749528269915966e-5L), + static_cast(0.14230900732435884e-5L), + }; + workspace[3] = tools::evaluate_polynomial(C3, z); + + static const T C4[] = { + static_cast(-0.0008618882909167117L), + static_cast(0.00078403922172006663L), + static_cast(-0.00029907248030319018L), + static_cast(-0.14638452578843418e-5L), + static_cast(0.66414982154651222e-4L), + static_cast(-0.39683650471794347e-4L), + static_cast(0.11375726970678419e-4L), + }; + workspace[4] = tools::evaluate_polynomial(C4, z); + + static const T C5[] = { + static_cast(-0.00033679855336635815L), + static_cast(-0.69728137583658578e-4L), + static_cast(0.00027727532449593921L), + static_cast(-0.00019932570516188848L), + static_cast(0.67977804779372078e-4L), + static_cast(0.1419062920643967e-6L), + static_cast(-0.13594048189768693e-4L), + static_cast(0.80184702563342015e-5L), + static_cast(-0.22914811765080952e-5L), + }; + workspace[5] = tools::evaluate_polynomial(C5, z); + + static const T C6[] = { + static_cast(0.00053130793646399222L), + static_cast(-0.00059216643735369388L), + static_cast(0.00027087820967180448L), + static_cast(0.79023532326603279e-6L), + static_cast(-0.81539693675619688e-4L), + static_cast(0.56116827531062497e-4L), + static_cast(-0.18329116582843376e-4L), + }; + workspace[6] = tools::evaluate_polynomial(C6, z); + + static const T C7[] = { + static_cast(0.00034436760689237767L), + static_cast(0.51717909082605922e-4L), + static_cast(-0.00033493161081142236L), + static_cast(0.0002812695154763237L), + static_cast(-0.00010976582244684731L), + }; + workspace[7] = tools::evaluate_polynomial(C7, z); + + static const T C8[] = { + static_cast(-0.00065262391859530942L), + static_cast(0.00083949872067208728L), + static_cast(-0.00043829709854172101L), + }; + workspace[8] = tools::evaluate_polynomial(C8, z); + workspace[9] = static_cast(-0.00059676129019274625L); + + T result = tools::evaluate_polynomial(workspace, 1/a); + result *= exp(-y) / sqrt(2 * constants::pi() * a); + if(x < a) + result = -result; + + result += boost::math::erfc(sqrt(y), pol) / 2; + + return result; +} +// +// This one is accurate for 24-bit mantissa's +// (IEEE float precision, or 10^-8) +// +template +T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<24> const *) +{ + BOOST_MATH_STD_USING // ADL of std functions + T sigma = (x - a) / a; + T phi = -boost::math::log1pmx(sigma, pol); + T y = a * phi; + T z = sqrt(2 * phi); + if(x < a) + z = -z; + + T workspace[3]; + + static const T C0[] = { + static_cast(-0.333333333L), + static_cast(0.0833333333L), + static_cast(-0.0148148148L), + static_cast(0.00115740741L), + static_cast(0.000352733686L), + static_cast(-0.000178755144L), + static_cast(0.391926318e-4L), + }; + workspace[0] = tools::evaluate_polynomial(C0, z); + + static const T C1[] = { + static_cast(-0.00185185185L), + static_cast(-0.00347222222L), + static_cast(0.00264550265L), + static_cast(-0.000990226337L), + static_cast(0.000205761317L), + }; + workspace[1] = tools::evaluate_polynomial(C1, z); + + static const T C2[] = { + static_cast(0.00413359788L), + static_cast(-0.00268132716L), + static_cast(0.000771604938L), + }; + workspace[2] = tools::evaluate_polynomial(C2, z); + + T result = tools::evaluate_polynomial(workspace, 1/a); + result *= exp(-y) / sqrt(2 * constants::pi() * a); + if(x < a) + result = -result; + + result += boost::math::erfc(sqrt(y), pol) / 2; + + return result; +} +// +// And finally, a version for 113-bit mantissa's +// (128-bit long doubles, or 10^-34). +// Note this one has been optimised for a > 200 +// It's use for a < 200 is not recomended, that would +// require many more terms in the polynomials. +// +template +T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<113> const *) +{ + BOOST_MATH_STD_USING // ADL of std functions + T sigma = (x - a) / a; + T phi = -boost::math::log1pmx(sigma, pol); + T y = a * phi; + T z = sqrt(2 * phi); + if(x < a) + z = -z; + + T workspace[14]; + + static const T C0[] = { + -0.333333333333333333333333333333333333L, + 0.0833333333333333333333333333333333333L, + -0.0148148148148148148148148148148148148L, + 0.00115740740740740740740740740740740741L, + 0.0003527336860670194003527336860670194L, + -0.000178755144032921810699588477366255144L, + 0.391926317852243778169704095630021556e-4L, + -0.218544851067999216147364295512443661e-5L, + -0.185406221071515996070179883622956325e-5L, + 0.829671134095308600501624213166443227e-6L, + -0.17665952736826079304360054245742403e-6L, + 0.670785354340149858036939710029613572e-8L, + 0.102618097842403080425739573227252951e-7L, + -0.438203601845335318655297462244719123e-8L, + 0.914769958223679023418248817633113681e-9L, + -0.255141939949462497668779537993887013e-10L, + -0.583077213255042506746408945040035798e-10L, + 0.243619480206674162436940696707789943e-10L, + -0.502766928011417558909054985925744366e-11L, + 0.110043920319561347708374174497293411e-12L, + 0.337176326240098537882769884169200185e-12L, + -0.13923887224181620659193661848957998e-12L, + 0.285348938070474432039669099052828299e-13L, + -0.513911183424257261899064580300494205e-15L, + -0.197522882943494428353962401580710912e-14L, + 0.809952115670456133407115668702575255e-15L, + -0.165225312163981618191514820265351162e-15L, + 0.253054300974788842327061090060267385e-17L, + 0.116869397385595765888230876507793475e-16L, + -0.477003704982048475822167804084816597e-17L, + 0.969912605905623712420709685898585354e-18L, + }; + workspace[0] = tools::evaluate_polynomial(C0, z); + + static const T C1[] = { + -0.00185185185185185185185185185185185185L, + -0.00347222222222222222222222222222222222L, + 0.0026455026455026455026455026455026455L, + -0.000990226337448559670781893004115226337L, + 0.000205761316872427983539094650205761317L, + -0.401877572016460905349794238683127572e-6L, + -0.180985503344899778370285914867533523e-4L, + 0.76491609160811100846374214980916921e-5L, + -0.16120900894563446003775221882217767e-5L, + 0.464712780280743434226135033938722401e-8L, + 0.137863344691572095931187533077488877e-6L, + -0.575254560351770496402194531835048307e-7L, + 0.119516285997781473243076536699698169e-7L, + -0.175432417197476476237547551202312502e-10L, + -0.100915437106004126274577504686681675e-8L, + 0.416279299184258263623372347219858628e-9L, + -0.856390702649298063807431562579670208e-10L, + 0.606721510160475861512701762169919581e-13L, + 0.716249896481148539007961017165545733e-11L, + -0.293318664377143711740636683615595403e-11L, + 0.599669636568368872330374527568788909e-12L, + -0.216717865273233141017100472779701734e-15L, + -0.497833997236926164052815522048108548e-13L, + 0.202916288237134247736694804325894226e-13L, + -0.413125571381061004935108332558187111e-14L, + 0.828651623988309644380188591057589316e-18L, + 0.341003088693333279336339355910600992e-15L, + -0.138541953028939715357034547426313703e-15L, + 0.281234665322887466568860332727259483e-16L, + }; + workspace[1] = tools::evaluate_polynomial(C1, z); + + static const T C2[] = { + 0.0041335978835978835978835978835978836L, + -0.00268132716049382716049382716049382716L, + 0.000771604938271604938271604938271604938L, + 0.200938786008230452674897119341563786e-5L, + -0.000107366532263651605215391223621676297L, + 0.529234488291201254164217127180090143e-4L, + -0.127606351886187277133779191392360117e-4L, + 0.34235787340961380741902003904747389e-7L, + 0.137219573090629332055943852926020279e-5L, + -0.629899213838005502290672234278391876e-6L, + 0.142806142060642417915846008822771748e-6L, + -0.204770984219908660149195854409200226e-9L, + -0.140925299108675210532930244154315272e-7L, + 0.622897408492202203356394293530327112e-8L, + -0.136704883966171134992724380284402402e-8L, + 0.942835615901467819547711211663208075e-12L, + 0.128722524000893180595479368872770442e-9L, + -0.556459561343633211465414765894951439e-10L, + 0.119759355463669810035898150310311343e-10L, + -0.416897822518386350403836626692480096e-14L, + -0.109406404278845944099299008640802908e-11L, + 0.4662239946390135746326204922464679e-12L, + -0.990510576390690597844122258212382301e-13L, + 0.189318767683735145056885183170630169e-16L, + 0.885922187259112726176031067028740667e-14L, + -0.373782039804640545306560251777191937e-14L, + 0.786883363903515525774088394065960751e-15L, + }; + workspace[2] = tools::evaluate_polynomial(C2, z); + + static const T C3[] = { + 0.000649434156378600823045267489711934156L, + 0.000229472093621399176954732510288065844L, + -0.000469189494395255712128140111679206329L, + 0.000267720632062838852962309752433209223L, + -0.756180167188397641072538191879755666e-4L, + -0.239650511386729665193314027333231723e-6L, + 0.110826541153473023614770299726861227e-4L, + -0.567495282699159656749963105701560205e-5L, + 0.14230900732435883914551894470580433e-5L, + -0.278610802915281422405802158211174452e-10L, + -0.16958404091930277289864168795820267e-6L, + 0.809946490538808236335278504852724081e-7L, + -0.191111684859736540606728140872727635e-7L, + 0.239286204398081179686413514022282056e-11L, + 0.206201318154887984369925818486654549e-8L, + -0.946049666185513217375417988510192814e-9L, + 0.215410497757749078380130268468744512e-9L, + -0.138882333681390304603424682490735291e-13L, + -0.218947616819639394064123400466489455e-10L, + 0.979099895117168512568262802255883368e-11L, + -0.217821918801809621153859472011393244e-11L, + 0.62088195734079014258166361684972205e-16L, + 0.212697836327973697696702537114614471e-12L, + -0.934468879151743333127396765626749473e-13L, + 0.204536712267828493249215913063207436e-13L, + }; + workspace[3] = tools::evaluate_polynomial(C3, z); + + static const T C4[] = { + -0.000861888290916711698604702719929057378L, + 0.00078403922172006662747403488144228885L, + -0.000299072480303190179733389609932819809L, + -0.146384525788434181781232535690697556e-5L, + 0.664149821546512218665853782451862013e-4L, + -0.396836504717943466443123507595386882e-4L, + 0.113757269706784190980552042885831759e-4L, + 0.250749722623753280165221942390057007e-9L, + -0.169541495365583060147164356781525752e-5L, + 0.890750753220530968882898422505515924e-6L, + -0.229293483400080487057216364891158518e-6L, + 0.295679413754404904696572852500004588e-10L, + 0.288658297427087836297341274604184504e-7L, + -0.141897394378032193894774303903982717e-7L, + 0.344635804994648970659527720474194356e-8L, + -0.230245171745280671320192735850147087e-12L, + -0.394092330280464052750697640085291799e-9L, + 0.186023389685045019134258533045185639e-9L, + -0.435632300505661804380678327446262424e-10L, + 0.127860010162962312660550463349930726e-14L, + 0.467927502665791946200382739991760062e-11L, + -0.214924647061348285410535341910721086e-11L, + 0.490881561480965216323649688463984082e-12L, + }; + workspace[4] = tools::evaluate_polynomial(C4, z); + + static const T C5[] = { + -0.000336798553366358150308767592718210002L, + -0.697281375836585777429398828575783308e-4L, + 0.00027727532449593920787336425196507501L, + -0.000199325705161888477003360405280844238L, + 0.679778047793720783881640176604435742e-4L, + 0.141906292064396701483392727105575757e-6L, + -0.135940481897686932784583938837504469e-4L, + 0.80184702563342015397192571980419684e-5L, + -0.229148117650809517038048790128781806e-5L, + -0.325247355129845395166230137750005047e-9L, + 0.346528464910852649559195496827579815e-6L, + -0.184471871911713432765322367374920978e-6L, + 0.482409670378941807563762631738989002e-7L, + -0.179894667217435153025754291716644314e-13L, + -0.630619450001352343517516981425944698e-8L, + 0.316241762877456793773762181540969623e-8L, + -0.784092425369742929000839303523267545e-9L, + }; + workspace[5] = tools::evaluate_polynomial(C5, z); + + static const T C6[] = { + 0.00053130793646399222316574854297762391L, + -0.000592166437353693882864836225604401187L, + 0.000270878209671804482771279183488328692L, + 0.790235323266032787212032944390816666e-6L, + -0.815396936756196875092890088464682624e-4L, + 0.561168275310624965003775619041471695e-4L, + -0.183291165828433755673259749374098313e-4L, + -0.307961345060330478256414192546677006e-8L, + 0.346515536880360908673728529745376913e-5L, + -0.202913273960586037269527254582695285e-5L, + 0.578879286314900370889997586203187687e-6L, + 0.233863067382665698933480579231637609e-12L, + -0.88286007463304835250508524317926246e-7L, + 0.474359588804081278032150770595852426e-7L, + -0.125454150207103824457130611214783073e-7L, + }; + workspace[6] = tools::evaluate_polynomial(C6, z); + + static const T C7[] = { + 0.000344367606892377671254279625108523655L, + 0.517179090826059219337057843002058823e-4L, + -0.000334931610811422363116635090580012327L, + 0.000281269515476323702273722110707777978L, + -0.000109765822446847310235396824500789005L, + -0.127410090954844853794579954588107623e-6L, + 0.277444515115636441570715073933712622e-4L, + -0.182634888057113326614324442681892723e-4L, + 0.578769494973505239894178121070843383e-5L, + 0.493875893393627039981813418398565502e-9L, + -0.105953670140260427338098566209633945e-5L, + 0.616671437611040747858836254004890765e-6L, + -0.175629733590604619378669693914265388e-6L, + }; + workspace[7] = tools::evaluate_polynomial(C7, z); + + static const T C8[] = { + -0.000652623918595309418922034919726622692L, + 0.000839498720672087279993357516764983445L, + -0.000438297098541721005061087953050560377L, + -0.696909145842055197136911097362072702e-6L, + 0.00016644846642067547837384572662326101L, + -0.000127835176797692185853344001461664247L, + 0.462995326369130429061361032704489636e-4L, + 0.455790986792270771162749294232219616e-8L, + -0.105952711258051954718238500312872328e-4L, + 0.678334290486516662273073740749269432e-5L, + -0.210754766662588042469972680229376445e-5L, + }; + workspace[8] = tools::evaluate_polynomial(C8, z); + + static const T C9[] = { + -0.000596761290192746250124390067179459605L, + -0.720489541602001055908571930225015052e-4L, + 0.000678230883766732836161951166000673426L, + -0.000640147526026275845100045652582354779L, + 0.000277501076343287044992374518205845463L, + 0.181970083804651510461686554030325202e-6L, + -0.847950711706850318239732559632810086e-4L, + 0.610519208250153101764709122740859458e-4L, + -0.210739201834048624082975255893773306e-4L, + }; + workspace[9] = tools::evaluate_polynomial(C9, z); + + static const T C10[] = { + 0.00133244544948006563712694993432717968L, + -0.00191443849856547752650089885832852254L, + 0.0011089369134596637339607446329267522L, + 0.993240412264229896742295262075817566e-6L, + -0.000508745012930931989848393025305956774L, + 0.00042735056665392884328432271160040444L, + -0.000168588537679107988033552814662382059L, + }; + workspace[10] = tools::evaluate_polynomial(C10, z); + + static const T C11[] = { + 0.00157972766073083495908785631307733022L, + 0.000162516262783915816898635123980270998L, + -0.00206334210355432762645284467690276817L, + 0.00213896861856890981541061922797693947L, + -0.00101085593912630031708085801712479376L, + }; + workspace[11] = tools::evaluate_polynomial(C11, z); + + static const T C12[] = { + -0.00407251211951401664727281097914544601L, + 0.00640336283380806979482363809026579583L, + -0.00404101610816766177473974858518094879L, + }; + workspace[12] = tools::evaluate_polynomial(C12, z); + workspace[13] = -0.0059475779383993002845382844736066323L; + + T result = tools::evaluate_polynomial(workspace, 1/a); + result *= exp(-y) / sqrt(2 * constants::pi() * a); + if(x < a) + result = -result; + + result += boost::math::erfc(sqrt(y), pol) / 2; + + return result; +} + + +} // namespace detail +} // namespace math +} // namespace math + + +#endif // BOOST_MATH_DETAIL_IGAMMA_LARGE diff --git a/include/boost/math/special_functions/detail/lgamma_small.hpp b/include/boost/math/special_functions/detail/lgamma_small.hpp new file mode 100644 index 000000000..c112c2784 --- /dev/null +++ b/include/boost/math/special_functions/detail/lgamma_small.hpp @@ -0,0 +1,507 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL +#define BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL + +namespace boost{ namespace math{ namespace detail{ + +// +// lgamma for small arguments: +// +template +T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<64>&, const Policy& /* l */, const L&) +{ + // This version uses rational approximations for small + // values of z accurate enough for 64-bit mantissas + // (80-bit long doubles), works well for 53-bit doubles as well. + // L is only used to select the Lanczos function. + + BOOST_MATH_STD_USING // for ADL of std names + T result = 0; + if(z < tools::epsilon()) + { + result = -log(z); + } + else if((zm1 == 0) || (zm2 == 0)) + { + // nothing to do, result is zero.... + } + else if(z > 2) + { + // + // Begin by performing argument reduction until + // z is in [2,3): + // + if(z >= 3) + { + do + { + z -= 1; + zm2 -= 1; + result += log(z); + }while(z >= 3); + // Update zm2, we need it below: + zm2 = z - 2; + } + + // + // Use the following form: + // + // lgamma(z) = (z-2)(z+1)(Y + R(z-2)) + // + // where R(z-2) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // R(z-2) has the following properties: + // + // At double: Max error found: 4.231e-18 + // At long double: Max error found: 1.987e-21 + // Maximum Deviation Found (approximation error): 5.900e-24 + // + static const T P[] = { + static_cast(-0.180355685678449379109e-1L), + static_cast(0.25126649619989678683e-1L), + static_cast(0.494103151567532234274e-1L), + static_cast(0.172491608709613993966e-1L), + static_cast(-0.259453563205438108893e-3L), + static_cast(-0.541009869215204396339e-3L), + static_cast(-0.324588649825948492091e-4L) + }; + static const T Q[] = { + static_cast(0.1e1), + static_cast(0.196202987197795200688e1L), + static_cast(0.148019669424231326694e1L), + static_cast(0.541391432071720958364e0L), + static_cast(0.988504251128010129477e-1L), + static_cast(0.82130967464889339326e-2L), + static_cast(0.224936291922115757597e-3L), + static_cast(-0.223352763208617092964e-6L) + }; + + static const float Y = 0.158963680267333984375e0f; + + T r = zm2 * (z + 1); + T R = tools::evaluate_polynomial(P, zm2); + R /= tools::evaluate_polynomial(Q, zm2); + + result += r * Y + r * R; + } + else + { + // + // If z is less than 1 use recurrance to shift to + // z in the interval [1,2]: + // + if(z < 1) + { + result += -log(z); + zm2 = zm1; + zm1 = z; + z += 1; + } + // + // Two approximations, on for z in [1,1.5] and + // one for z in [1.5,2]: + // + if(z <= 1.5) + { + // + // Use the following form: + // + // lgamma(z) = (z-1)(z-2)(Y + R(z-1)) + // + // where R(z-1) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // R(z-1) has the following properties: + // + // At double precision: Max error found: 1.230011e-17 + // At 80-bit long double precision: Max error found: 5.631355e-21 + // Maximum Deviation Found: 3.139e-021 + // Expected Error Term: 3.139e-021 + + // + static const float Y = 0.52815341949462890625f; + + static const T P[] = { + static_cast(0.490622454069039543534e-1L), + static_cast(-0.969117530159521214579e-1L), + static_cast(-0.414983358359495381969e0L), + static_cast(-0.406567124211938417342e0L), + static_cast(-0.158413586390692192217e0L), + static_cast(-0.240149820648571559892e-1L), + static_cast(-0.100346687696279557415e-2L) + }; + static const T Q[] = { + static_cast(0.1e1L), + static_cast(0.302349829846463038743e1L), + static_cast(0.348739585360723852576e1L), + static_cast(0.191415588274426679201e1L), + static_cast(0.507137738614363510846e0L), + static_cast(0.577039722690451849648e-1L), + static_cast(0.195768102601107189171e-2L) + }; + + T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1); + T prefix = zm1 * zm2; + + result += prefix * Y + prefix * r; + } + else + { + // + // Use the following form: + // + // lgamma(z) = (2-z)(1-z)(Y + R(2-z)) + // + // where R(2-z) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // R(2-z) has the following properties: + // + // At double precision, max error found: 1.797565e-17 + // At 80-bit long double precision, max error found: 9.306419e-21 + // Maximum Deviation Found: 2.151e-021 + // Expected Error Term: 2.150e-021 + // + static const float Y = 0.452017307281494140625f; + + static const T P[] = { + static_cast(-0.292329721830270012337e-1L), + static_cast(0.144216267757192309184e0L), + static_cast(-0.142440390738631274135e0L), + static_cast(0.542809694055053558157e-1L), + static_cast(-0.850535976868336437746e-2L), + static_cast(0.431171342679297331241e-3L) + }; + static const T Q[] = { + static_cast(0.1e1), + static_cast(-0.150169356054485044494e1L), + static_cast(0.846973248876495016101e0L), + static_cast(-0.220095151814995745555e0L), + static_cast(0.25582797155975869989e-1L), + static_cast(-0.100666795539143372762e-2L), + static_cast(-0.827193521891290553639e-6L) + }; + T r = zm2 * zm1; + T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2); + + result += r * Y + r * R; + } + } + return result; +} +template +T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<113>&, const Policy& /* l */, const L&) +{ + // + // This version uses rational approximations for small + // values of z accurate enough for 113-bit mantissas + // (128-bit long doubles). + // + BOOST_MATH_STD_USING // for ADL of std names + T result = 0; + if(z < tools::epsilon()) + { + result = -log(z); + BOOST_MATH_INSTRUMENT_CODE(result); + } + else if((zm1 == 0) || (zm2 == 0)) + { + // nothing to do, result is zero.... + } + else if(z > 2) + { + // + // Begin by performing argument reduction until + // z is in [2,3): + // + if(z >= 3) + { + do + { + z -= 1; + result += log(z); + }while(z >= 3); + zm2 = z - 2; + } + BOOST_MATH_INSTRUMENT_CODE(zm2); + BOOST_MATH_INSTRUMENT_CODE(z); + BOOST_MATH_INSTRUMENT_CODE(result); + + // + // Use the following form: + // + // lgamma(z) = (z-2)(z+1)(Y + R(z-2)) + // + // where R(z-2) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // Maximum Deviation Found (approximation error) 3.73e-37 + + static const T P[] = { + -0.018035568567844937910504030027467476655L, + 0.013841458273109517271750705401202404195L, + 0.062031842739486600078866923383017722399L, + 0.052518418329052161202007865149435256093L, + 0.01881718142472784129191838493267755758L, + 0.0025104830367021839316463675028524702846L, + -0.00021043176101831873281848891452678568311L, + -0.00010249622350908722793327719494037981166L, + -0.11381479670982006841716879074288176994e-4L, + -0.49999811718089980992888533630523892389e-6L, + -0.70529798686542184668416911331718963364e-8L + }; + static const T Q[] = { + 1L, + 2.5877485070422317542808137697939233685L, + 2.8797959228352591788629602533153837126L, + 1.8030885955284082026405495275461180977L, + 0.69774331297747390169238306148355428436L, + 0.17261566063277623942044077039756583802L, + 0.02729301254544230229429621192443000121L, + 0.0026776425891195270663133581960016620433L, + 0.00015244249160486584591370355730402168106L, + 0.43997034032479866020546814475414346627e-5L, + 0.46295080708455613044541885534408170934e-7L, + -0.93326638207459533682980757982834180952e-11L, + 0.42316456553164995177177407325292867513e-13L + }; + + T R = tools::evaluate_polynomial(P, zm2); + R /= tools::evaluate_polynomial(Q, zm2); + + static const float Y = 0.158963680267333984375F; + + T r = zm2 * (z + 1); + + result += r * Y + r * R; + BOOST_MATH_INSTRUMENT_CODE(result); + } + else + { + // + // If z is less than 1 use recurrance to shift to + // z in the interval [1,2]: + // + if(z < 1) + { + result += -log(z); + zm2 = zm1; + zm1 = z; + z += 1; + } + BOOST_MATH_INSTRUMENT_CODE(result); + BOOST_MATH_INSTRUMENT_CODE(z); + BOOST_MATH_INSTRUMENT_CODE(zm2); + // + // Three approximations, on for z in [1,1.35], [1.35,1.625] and [1.625,1] + // + if(z <= 1.35) + { + // + // Use the following form: + // + // lgamma(z) = (z-1)(z-2)(Y + R(z-1)) + // + // where R(z-1) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // R(z-1) has the following properties: + // + // Maximum Deviation Found (approximation error) 1.659e-36 + // Expected Error Term (theoretical error) 1.343e-36 + // Max error found at 128-bit long double precision 1.007e-35 + // + static const float Y = 0.54076099395751953125f; + + static const T P[] = { + 0.036454670944013329356512090082402429697L, + -0.066235835556476033710068679907798799959L, + -0.67492399795577182387312206593595565371L, + -1.4345555263962411429855341651960000166L, + -1.4894319559821365820516771951249649563L, + -0.87210277668067964629483299712322411566L, + -0.29602090537771744401524080430529369136L, + -0.0561832587517836908929331992218879676L, + -0.0053236785487328044334381502530383140443L, + -0.00018629360291358130461736386077971890789L, + -0.10164985672213178500790406939467614498e-6L, + 0.13680157145361387405588201461036338274e-8L + }; + static const T Q[] = { + 1, + 4.9106336261005990534095838574132225599L, + 10.258804800866438510889341082793078432L, + 11.88588976846826108836629960537466889L, + 8.3455000546999704314454891036700998428L, + 3.6428823682421746343233362007194282703L, + 0.97465989807254572142266753052776132252L, + 0.15121052897097822172763084966793352524L, + 0.012017363555383555123769849654484594893L, + 0.0003583032812720649835431669893011257277L + }; + + T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1); + T prefix = zm1 * zm2; + + result += prefix * Y + prefix * r; + BOOST_MATH_INSTRUMENT_CODE(result); + } + else if(z <= 1.625) + { + // + // Use the following form: + // + // lgamma(z) = (2-z)(1-z)(Y + R(2-z)) + // + // where R(2-z) is a rational approximation optimised for + // low absolute error - as long as it's absolute error + // is small compared to the constant Y - then any rounding + // error in it's computation will get wiped out. + // + // R(2-z) has the following properties: + // + // Max error found at 128-bit long double precision 9.634e-36 + // Maximum Deviation Found (approximation error) 1.538e-37 + // Expected Error Term (theoretical error) 2.350e-38 + // + static const float Y = 0.483787059783935546875f; + + static const T P[] = { + -0.017977422421608624353488126610933005432L, + 0.18484528905298309555089509029244135703L, + -0.40401251514859546989565001431430884082L, + 0.40277179799147356461954182877921388182L, + -0.21993421441282936476709677700477598816L, + 0.069595742223850248095697771331107571011L, + -0.012681481427699686635516772923547347328L, + 0.0012489322866834830413292771335113136034L, + -0.57058739515423112045108068834668269608e-4L, + 0.8207548771933585614380644961342925976e-6L + }; + static const T Q[] = { + 1, + -2.9629552288944259229543137757200262073L, + 3.7118380799042118987185957298964772755L, + -2.5569815272165399297600586376727357187L, + 1.0546764918220835097855665680632153367L, + -0.26574021300894401276478730940980810831L, + 0.03996289731752081380552901986471233462L, + -0.0033398680924544836817826046380586480873L, + 0.00013288854760548251757651556792598235735L, + -0.17194794958274081373243161848194745111e-5L + }; + T r = zm2 * zm1; + T R = tools::evaluate_polynomial(P, 0.625 - zm1) / tools::evaluate_polynomial(Q, 0.625 - zm1); + + result += r * Y + r * R; + BOOST_MATH_INSTRUMENT_CODE(result); + } + else + { + // + // Same form as above. + // + // Max error found (at 128-bit long double precision) 1.831e-35 + // Maximum Deviation Found (approximation error) 8.588e-36 + // Expected Error Term (theoretical error) 1.458e-36 + // + static const float Y = 0.443811893463134765625f; + + static const T P[] = { + -0.021027558364667626231512090082402429494L, + 0.15128811104498736604523586803722368377L, + -0.26249631480066246699388544451126410278L, + 0.21148748610533489823742352180628489742L, + -0.093964130697489071999873506148104370633L, + 0.024292059227009051652542804957550866827L, + -0.0036284453226534839926304745756906117066L, + 0.0002939230129315195346843036254392485984L, + -0.11088589183158123733132268042570710338e-4L, + 0.13240510580220763969511741896361984162e-6L + }; + static const T Q[] = { + 1, + -2.4240003754444040525462170802796471996L, + 2.4868383476933178722203278602342786002L, + -1.4047068395206343375520721509193698547L, + 0.47583809087867443858344765659065773369L, + -0.09865724264554556400463655444270700132L, + 0.012238223514176587501074150988445109735L, + -0.00084625068418239194670614419707491797097L, + 0.2796574430456237061420839429225710602e-4L, + -0.30202973883316730694433702165188835331e-6L + }; + // (2 - x) * (1 - x) * (c + R(2 - x)) + T r = zm2 * zm1; + T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2); + + result += r * Y + r * R; + BOOST_MATH_INSTRUMENT_CODE(result); + } + } + BOOST_MATH_INSTRUMENT_CODE(result); + return result; +} +template +T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<0>&, const Policy& pol, const L&) +{ + // + // No rational approximations are available because either + // T has no numeric_limits support (so we can't tell how + // many digits it has), or T has more digits than we know + // what to do with.... we do have a Lanczos approximation + // though, and that can be used to keep errors under control. + // + BOOST_MATH_STD_USING // for ADL of std names + T result = 0; + if(z < tools::epsilon()) + { + result = -log(z); + } + else if(z < 0.5) + { + // taking the log of tgamma reduces the error, no danger of overflow here: + result = log(gamma_imp(z, pol, L())); + } + else if(z >= 3) + { + // taking the log of tgamma reduces the error, no danger of overflow here: + result = log(gamma_imp(z, pol, L())); + } + else if(z >= 1.5) + { + // special case near 2: + T dz = zm2; + result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e()); + result += boost::math::log1p(dz / (L::g() + T(1.5)), pol) * T(1.5); + result += boost::math::log1p(L::lanczos_sum_near_2(dz), pol); + } + else + { + // special case near 1: + T dz = zm1; + result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e()); + result += boost::math::log1p(dz / (L::g() + T(0.5)), pol) / 2; + result += boost::math::log1p(L::lanczos_sum_near_1(dz), pol); + } + return result; +} + +}}} // namespaces + +#endif // BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL diff --git a/include/boost/math/special_functions/detail/series.hpp b/include/boost/math/special_functions/detail/series.hpp deleted file mode 100644 index 1d30d8b63..000000000 --- a/include/boost/math/special_functions/detail/series.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// (C) Copyright John Maddock 2005. -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_MATH_SERIES_INCLUDED -#define BOOST_MATH_SERIES_INCLUDED - -#include - -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std{ using ::pow; using ::fabs; } -#endif - - -namespace boost{ namespace math{ namespace detail{ - -// -// Algorithm kahan_sum_series invokes Functor func until the N'th -// term is too small to have any effect on the total, the terms -// are added using the Kahan summation method. -// -// CAUTION: Optimizing compilers combined with extended-precision -// machine registers conspire to render this algorithm partly broken: -// double rounding of intermediate terms (first to a long double machine -// register, and then to a double result) cause the rounding error computed -// by the algorithm to be off by up to 1ulp. However this occurs rarely, and -// in any case the result is still much better than a naive summation. -// -template -typename Functor::result_type kahan_sum_series(Functor& func, int bits) -{ - typedef typename Functor::result_type result_type; - result_type factor = std::pow(result_type(2), bits); - result_type result = func(); - result_type next_term, y, t; - result_type carry = 0; - do{ - next_term = func(); - y = next_term - carry; - t = result + y; - carry = t - result; - carry -= y; - result = t; - } - while(std::fabs(result) < std::fabs(factor * next_term)); - return result; -} - -} } } // namespaces - -#endif // BOOST_MATH_SERIES_INCLUDED diff --git a/include/boost/math/special_functions/detail/simple_complex.hpp b/include/boost/math/special_functions/detail/simple_complex.hpp new file mode 100644 index 000000000..e01cf5efb --- /dev/null +++ b/include/boost/math/special_functions/detail/simple_complex.hpp @@ -0,0 +1,167 @@ +// Copyright (c) 2007 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_DETAIL_SIMPLE_COMPLEX_HPP +#define BOOST_MATH_SF_DETAIL_SIMPLE_COMPLEX_HPP + +namespace boost{ namespace math{ namespace detail{ namespace sc{ + +template +class simple_complex +{ +public: + simple_complex() : r(0), i(0) {} + simple_complex(T a) : r(a) {} + template + simple_complex(U a) : r(a) {} + simple_complex(T a, T b) : r(a), i(b) {} + + simple_complex& operator += (const simple_complex& o) + { + r += o.r; + i += o.i; + return *this; + } + simple_complex& operator -= (const simple_complex& o) + { + r -= o.r; + i -= o.i; + return *this; + } + simple_complex& operator *= (const simple_complex& o) + { + T lr = r * o.r - i * o.i; + T li = i * o.r + r * o.i; + r = lr; + i = li; + return *this; + } + simple_complex& operator /= (const simple_complex& o) + { + BOOST_MATH_STD_USING + T lr; + T li; + if(fabs(o.r) > fabs(o.i)) + { + T rat = o.i / o.r; + lr = r + i * rat; + li = i - r * rat; + rat = o.r + o.i * rat; + lr /= rat; + li /= rat; + } + else + { + T rat = o.r / o.i; + lr = i + r * rat; + li = i * rat - r; + rat = o.r * rat + o.i; + lr /= rat; + li /= rat; + } + r = lr; + i = li; + return *this; + } + bool operator == (const simple_complex& o) + { + return (r == o.r) && (i == o.i); + } + bool operator != (const simple_complex& o) + { + return !((r == o.r) && (i == o.i)); + } + bool operator == (const T& o) + { + return (r == o) && (i == 0); + } + simple_complex& operator += (const T& o) + { + r += o; + return *this; + } + simple_complex& operator -= (const T& o) + { + r -= o; + return *this; + } + simple_complex& operator *= (const T& o) + { + r *= o; + i *= o; + return *this; + } + simple_complex& operator /= (const T& o) + { + r /= o; + i /= o; + return *this; + } + T real()const + { + return r; + } + T imag()const + { + return i; + } +private: + T r, i; +}; + +template +inline simple_complex operator+(const simple_complex& a, const simple_complex& b) +{ + simple_complex result(a); + result += b; + return result; +} + +template +inline simple_complex operator-(const simple_complex& a, const simple_complex& b) +{ + simple_complex result(a); + result -= b; + return result; +} + +template +inline simple_complex operator*(const simple_complex& a, const simple_complex& b) +{ + simple_complex result(a); + result *= b; + return result; +} + +template +inline simple_complex operator/(const simple_complex& a, const simple_complex& b) +{ + simple_complex result(a); + result /= b; + return result; +} + +template +inline T real(const simple_complex& c) +{ + return c.real(); +} + +template +inline T imag(const simple_complex& c) +{ + return c.imag(); +} + +template +inline T abs(const simple_complex& c) +{ + return hypot(c.real(), c.imag()); +} + +}}}} // namespace + +#endif + diff --git a/include/boost/math/special_functions/detail/t_distribution_inv.hpp b/include/boost/math/special_functions/detail/t_distribution_inv.hpp new file mode 100644 index 000000000..2af3cb957 --- /dev/null +++ b/include/boost/math/special_functions/detail/t_distribution_inv.hpp @@ -0,0 +1,509 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_DETAIL_INV_T_HPP +#define BOOST_MATH_SF_DETAIL_INV_T_HPP + +#include + +namespace boost{ namespace math{ namespace detail{ + +// +// The main method used is due to Hill: +// +// G. W. Hill, Algorithm 396, Student’s t-Quantiles, +// Communications of the ACM, 13(10): 619-620, Oct., 1970. +// +template +T inverse_students_t_hill(T ndf, T u, const Policy& pol) +{ + BOOST_MATH_STD_USING + BOOST_ASSERT(u <= 0.5); + + T a, b, c, d, q, x, y; + + if (ndf > 1e20f) + return -boost::math::erfc_inv(2 * u, pol) * constants::root_two(); + + a = 1 / (ndf - 0.5f); + b = 48 / (a * a); + c = ((20700 * a / b - 98) * a - 16) * a + 96.36f; + d = ((94.5f / (b + c) - 3) / b + 1) * sqrt(a * constants::pi() / 2) * ndf; + y = pow(d * 2 * u, 2 / ndf); + + if (y > (0.05f + a)) + { + // + // Asymptotic inverse expansion about normal: + // + x = -boost::math::erfc_inv(2 * u, pol) * constants::root_two(); + y = x * x; + + if (ndf < 5) + c += 0.3f * (ndf - 4.5f) * (x + 0.6f); + c += (((0.05f * d * x - 5) * x - 7) * x - 2) * x + b; + y = (((((0.4f * y + 6.3f) * y + 36) * y + 94.5f) / c - y - 3) / b + 1) * x; + y = boost::math::expm1(a * y * y, pol); + } + else + { + y = ((1 / (((ndf + 6) / (ndf * y) - 0.089f * d - 0.822f) + * (ndf + 2) * 3) + 0.5 / (ndf + 4)) * y - 1) + * (ndf + 1) / (ndf + 2) + 1 / y; + } + q = sqrt(ndf * y); + + return -q; +} +// +// Tail and body series are due to Shaw: +// +// www.mth.kcl.ac.uk/˜shaww/web_page/papers/Tdistribution06.pdf +// +// Shaw, W.T., 2006, "Sampling Student’s T distribution – use of +// the inverse cumulative distribution function." +// Journal of Computational Finance, Vol 9 Issue 4, pp 37-73, Summer 2006 +// +template +T inverse_students_t_tail_series(T df, T v, const Policy& pol) +{ + BOOST_MATH_STD_USING + // Tail series expansion, see section 6 of Shaw's paper. + // w is calculated using Eq 60: + T w = boost::math::tgamma_delta_ratio(df / 2, constants::half(), pol) + * sqrt(df * constants::pi()) * v; + // define some variables: + T np2 = df + 2; + T np4 = df + 4; + T np6 = df + 6; + // + // Calculate the coefficients d(k), these depend only on the + // number of degrees of freedom df, so at least in theory + // we could tabulate these for fixed df, see p15 of Shaw: + // + T d[7] = { 1, }; + d[1] = -(df + 1) / (2 * np2); + np2 *= (df + 2); + d[2] = -df * (df + 1) * (df + 3) / (8 * np2 * np4); + np2 *= df + 2; + d[3] = -df * (df + 1) * (df + 5) * (((3 * df) + 7) * df -2) / (48 * np2 * np4 * np6); + np2 *= (df + 2); + np4 *= (df + 4); + d[4] = -df * (df + 1) * (df + 7) * + ( (((((15 * df) + 154) * df + 465) * df + 286) * df - 336) * df + 64 ) + / (384 * np2 * np4 * np6 * (df + 8)); + np2 *= (df + 2); + d[5] = -df * (df + 1) * (df + 3) * (df + 9) + * (((((((35 * df + 452) * df + 1573) * df + 600) * df - 2020) * df) + 928) * df -128) + / (1280 * np2 * np4 * np6 * (df + 8) * (df + 10)); + np2 *= (df + 2); + np4 *= (df + 4); + np6 *= (df + 6); + d[6] = -df * (df + 1) * (df + 11) + * ((((((((((((945 * df) + 31506) * df + 425858) * df + 2980236) * df + 11266745) * df + 20675018) * df + 7747124) * df - 22574632) * df - 8565600) * df + 18108416) * df - 7099392) * df + 884736) + / (46080 * np2 * np4 * np6 * (df + 8) * (df + 10) * (df +12)); + // + // Now bring everthing together to provide the result, + // this is Eq 62 of Shaw: + // + T rn = sqrt(df); + T div = pow(rn * w, 1 / df); + T power = div * div; + T result = tools::evaluate_polynomial(d, power); + result *= rn; + result /= div; + return -result; +} + +template +T inverse_students_t_body_series(T df, T u, const Policy& pol) +{ + BOOST_MATH_STD_USING + // + // Body series for small N: + // + // Start with Eq 56 of Shaw: + // + T v = boost::math::tgamma_delta_ratio(df / 2, constants::half(), pol) + * sqrt(df * constants::pi()) * (u - constants::half()); + // + // Workspace for the polynomial coefficients: + // + T c[11] = { 0, 1, }; + // + // Figure out what the coefficients are, note these depend + // only on the degrees of freedom (Eq 57 of Shaw): + // + c[2] = T(1) / 6 + T(1) / (6 * df); + T in = 1 / df; + c[3] = (((T(1) / 120) * in) + (T(1) / 15)) * in + (T(7) / 120); + c[4] = ((((T(1) / 5040) * in + (T(1) / 560)) * in + (T(3) / 112)) * in + T(127) / 5040); + c[5] = ((((T(1) / 362880) * in + (T(17) / 45360)) * in + (T(67) / 60480)) * in + (T(479) / 45360)) * in + (T(4369) / 362880); + c[6] = ((((((T(1) / 39916800) * in + (T(2503) / 39916800)) * in + (T(11867) / 19958400)) * in + (T(1285) / 798336)) * in + (T(153161) / 39916800)) * in + (T(34807) / 5702400)); + c[7] = (((((((T(1) / 6227020800LL) * in + (T(37) / 2402400)) * in + + (T(339929) / 2075673600LL)) * in + (T(67217) / 97297200)) * in + + (T(870341) / 691891200LL)) * in + (T(70691) / 64864800LL)) * in + + (T(20036983LL) / 6227020800LL)); + c[8] = (((((((T(1) / 1307674368000LL) * in + (T(1042243LL) / 261534873600LL)) * in + + (T(21470159) / 435891456000LL)) * in + (T(326228899LL) / 1307674368000LL)) * in + + (T(843620579) / 1307674368000LL)) * in + (T(332346031LL) / 435891456000LL)) * in + + (T(43847599) / 1307674368000LL)) * in + (T(2280356863LL) / 1307674368000LL); + c[9] = (((((((((T(1) / 355687428096000LL)) * in + (T(24262727LL) / 22230464256000LL)) * in + + (T(123706507LL) / 8083805184000LL)) * in + (T(404003599LL) / 4446092851200LL)) * in + + (T(51811946317LL) / 177843714048000LL)) * in + (T(91423417LL) / 177843714048LL)) * in + + (T(32285445833LL) / 88921857024000LL)) * in + (T(531839683LL) / 1710035712000LL)) * in + + (T(49020204823LL) / 50812489728000LL); + c[10] = (((((((((T(1) / 121645100408832000LL) * in + + (T(4222378423LL) / 13516122267648000LL)) * in + + (T(49573465457LL) / 10137091700736000LL)) * in + + (T(176126809LL) / 5304600576000LL)) * in + + (T(44978231873LL) / 355687428096000LL)) * in + + (T(5816850595639LL) / 20274183401472000LL)) * in + + (T(73989712601LL) / 206879422464000LL)) * in + + (T(26591354017LL) / 259925428224000LL)) * in + + (T(14979648446341LL) / 40548366802944000LL)) * in + + (T(65967241200001LL) / 121645100408832000LL); + // + // The result is then a polynomial in v (see Eq 56 of Shaw): + // + return tools::evaluate_odd_polynomial(c, v); +} + +template +T inverse_students_t(T df, T u, T v, const Policy& pol, bool* pexact = 0) +{ + // + // df = number of degrees of freedom. + // u = probablity. + // v = 1 - u. + // l = lanczos type to use. + // + BOOST_MATH_STD_USING + bool invert = false; + T result = 0; + if(pexact) + *pexact = false; + if(u > v) + { + // function is symmetric, invert it: + std::swap(u, v); + invert = true; + } + if((floor(df) == df) && (df < 20)) + { + // + // we have integer degrees of freedom, try for the special + // cases first: + // + T tolerance = ldexp(1.0f, (2 * policies::digits()) / 3); + + switch(boost::math::tools::real_cast(df)) + { + case 1: + { + // + // df = 1 is the same as the Cauchy distribution, see + // Shaw Eq 35: + // + if(u == 0.5) + result = 0; + else + result = -cos(constants::pi() * u) / sin(constants::pi() * u); + if(pexact) + *pexact = true; + break; + } + case 2: + { + // + // df = 2 has an exact result, see Shaw Eq 36: + // + result =(2 * u - 1) / sqrt(2 * u * v); + if(pexact) + *pexact = true; + break; + } + case 4: + { + // + // df = 4 has an exact result, see Shaw Eq 38 & 39: + // + T alpha = 4 * u * v; + T root_alpha = sqrt(alpha); + T r = 4 * cos(acos(root_alpha) / 3) / root_alpha; + T x = sqrt(r - 4); + result = u - 0.5f < 0 ? -x : x; + if(pexact) + *pexact = true; + break; + } + case 6: + { + // + // We get numeric overflow in this area: + // + if(u < 1e-150) + return (invert ? -1 : 1) * inverse_students_t_hill(df, u, pol); + // + // Newton-Raphson iteration of a polynomial case, + // choice of seed value is taken from Shaw's online + // supplement: + // + T a = 4 * (u - u * u);//1 - 4 * (u - 0.5f) * (u - 0.5f); + T b = boost::math::cbrt(a); + static const T c = 0.85498797333834849467655443627193L; + T p = 6 * (1 + c * (1 / b - 1)); + T p0; + do{ + T p2 = p * p; + T p4 = p2 * p2; + T p5 = p * p4; + p0 = p; + // next term is given by Eq 41: + p = 2 * (8 * a * p5 - 270 * p2 + 2187) / (5 * (4 * a * p4 - 216 * p - 243)); + }while(fabs((p - p0) / p) > tolerance); + // + // Use Eq 45 to extract the result: + // + p = sqrt(p - df); + result = (u - 0.5f) < 0 ? -p : p; + break; + } +#if 0 + // + // These are Shaw's "exact" but iterative solutions + // for even df, the numerical accuracy of these is + // rather less than Hill's method, so these are disabled + // for now, which is a shame because they are reasonably + // quick to evaluate... + // + case 8: + { + // + // Newton-Raphson iteration of a polynomial case, + // choice of seed value is taken from Shaw's online + // supplement: + // + static const T c8 = 0.85994765706259820318168359251872L; + T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f); + T b = pow(a, T(1) / 4); + T p = 8 * (1 + c8 * (1 / b - 1)); + T p0 = p; + do{ + T p5 = p * p; + p5 *= p5 * p; + p0 = p; + // Next term is given by Eq 42: + p = 2 * (3 * p + (640 * (160 + p * (24 + p * (p + 4)))) / (-5120 + p * (-2048 - 960 * p + a * p5))) / 7; + }while(fabs((p - p0) / p) > tolerance); + // + // Use Eq 45 to extract the result: + // + p = sqrt(p - df); + result = (u - 0.5f) < 0 ? -p : p; + break; + } + case 10: + { + // + // Newton-Raphson iteration of a polynomial case, + // choice of seed value is taken from Shaw's online + // supplement: + // + static const T c10 = 0.86781292867813396759105692122285L; + T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f); + T b = pow(a, T(1) / 5); + T p = 10 * (1 + c10 * (1 / b - 1)); + T p0; + do{ + T p6 = p * p; + p6 *= p6 * p6; + p0 = p; + // Next term given by Eq 43: + p = (8 * p) / 9 + (218750 * (21875 + 4 * p * (625 + p * (75 + 2 * p * (5 + p))))) / + (9 * (-68359375 + 8 * p * (-2343750 + p * (-546875 - 175000 * p + 8 * a * p6)))); + }while(fabs((p - p0) / p) > tolerance); + // + // Use Eq 45 to extract the result: + // + p = sqrt(p - df); + result = (u - 0.5f) < 0 ? -p : p; + break; + } +#endif + default: + goto calculate_real; + } + } + else + { +calculate_real: + if(df < 3) + { + // + // Use a roughly linear scheme to choose between Shaw's + // tail series and body series: + // + T crossover = 0.2742f - df * 0.0242143f; + if(u > crossover) + { + result = boost::math::detail::inverse_students_t_body_series(df, u, pol); + } + else + { + result = boost::math::detail::inverse_students_t_tail_series(df, u, pol); + } + } + else + { + // + // Use Hill's method except in the exteme tails + // where we use Shaw's tail series. + // The crossover point is roughly exponential in -df: + // + T crossover = ldexp(1.0f, tools::real_cast(df / -0.654f)); + if(u > crossover) + { + result = boost::math::detail::inverse_students_t_hill(df, u, pol); + } + else + { + result = boost::math::detail::inverse_students_t_tail_series(df, u, pol); + } + } + } + return invert ? -result : result; +} + +template +inline T find_ibeta_inv_from_t_dist(T a, T p, T q, T* py, const Policy& pol) +{ + T u = (p > q) ? 0.5f - q / 2 : p / 2; + T v = 1 - u; // u < 0.5 so no cancellation error + T df = a * 2; + T t = boost::math::detail::inverse_students_t(df, u, v, pol); + T x = df / (df + t * t); + *py = t * t / (df + t * t); + return x; +} + +template +inline T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::false_*) +{ + BOOST_MATH_STD_USING + // + // Need to use inverse incomplete beta to get + // required precision so not so fast: + // + T probability = (p > 0.5) ? 1 - p : p; + T t, x, y; + x = ibeta_inv(df / 2, T(0.5), 2 * probability, &y, pol); + if(df * y > tools::max_value() * x) + t = policies::raise_overflow_error("boost::math::students_t_quantile<%1%>(%1%,%1%)", 0, pol); + else + t = sqrt(df * y / x); + // + // Figure out sign based on the size of p: + // + if(p < 0.5) + t = -t; + return t; +} + +template +T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::true_*) +{ + BOOST_MATH_STD_USING + bool invert = false; + if((df < 2) && (floor(df) != df)) + return boost::math::detail::fast_students_t_quantile_imp(df, p, pol, static_cast(0)); + if(p > 0.5) + { + p = 1 - p; + invert = true; + } + // + // Get an estimate of the result: + // + bool exact; + T t = inverse_students_t(df, p, 1-p, pol, &exact); + if((t == 0) || exact) + return invert ? -t : t; // can't do better! + // + // Change variables to inverse incomplete beta: + // + T t2 = t * t; + T xb = df / (df + t2); + T y = t2 / (df + t2); + T a = df / 2; + // + // t can be so large that x underflows, + // just return our estimate in that case: + // + if(xb == 0) + return t; + // + // Get incomplete beta and it's derivative: + // + T f1; + T f0 = xb < y ? ibeta_imp(a, constants::half(), xb, pol, false, true, &f1) + : ibeta_imp(constants::half(), a, y, pol, true, true, &f1); + + // Get cdf from incomplete beta result: + T p0 = f0 / 2 - p; + // Get pdf from derivative: + T p1 = f1 * sqrt(y * xb * xb * xb / df); + // + // Second derivative divided by p1: + // + // yacas gives: + // + // In> PrettyForm(Simplify(D(t) (1 + t^2/v) ^ (-(v+1)/2))) + // + // | | v + 1 | | + // | -| ----- + 1 | | + // | | 2 | | + // -| | 2 | | + // | | t | | + // | | -- + 1 | | + // | ( v + 1 ) * | v | * t | + // --------------------------------------------- + // v + // + // Which after some manipulation is: + // + // -p1 * t * (df + 1) / (t^2 + df) + // + T p2 = t * (df + 1) / (t * t + df); + // Halley step: + t = fabs(t); + t += p0 / (p1 + p0 * p2 / 2); + return !invert ? -t : t; +} + +template +inline T fast_students_t_quantile(T df, T p, const Policy& pol) +{ + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + typedef mpl::bool_< + (std::numeric_limits::digits <= 53) + && + (std::numeric_limits::is_specialized)> tag_type; + return policies::checked_narrowing_cast(fast_students_t_quantile_imp(static_cast(df), static_cast(p), pol, static_cast(0)), "boost::math::students_t_quantile<%1%>(%1%,%1%,%1%)"); +} + +}}} // namespaces + +#endif // BOOST_MATH_SF_DETAIL_INV_T_HPP + + diff --git a/include/boost/math/special_functions/detail/unchecked_factorial.hpp b/include/boost/math/special_functions/detail/unchecked_factorial.hpp new file mode 100644 index 000000000..f58b54ed5 --- /dev/null +++ b/include/boost/math/special_functions/detail/unchecked_factorial.hpp @@ -0,0 +1,397 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SP_UC_FACTORIALS_HPP +#define BOOST_MATH_SP_UC_FACTORIALS_HPP + +#include +#ifdef BOOST_MSVC +#pragma warning(push) // Temporary until lexical cast fixed. +#pragma warning(disable: 4127 4701) +#endif +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +#include +#include + +namespace boost { namespace math +{ +// Forward declarations: +template +struct max_factorial; + +// efinitions: +template <> +inline float unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(float)) +{ + static const boost::array factorials = {{ + 1.0F, + 1.0F, + 2.0F, + 6.0F, + 24.0F, + 120.0F, + 720.0F, + 5040.0F, + 40320.0F, + 362880.0F, + 3628800.0F, + 39916800.0F, + 479001600.0F, + 6227020800.0F, + 87178291200.0F, + 1307674368000.0F, + 20922789888000.0F, + 355687428096000.0F, + 6402373705728000.0F, + 121645100408832000.0F, + 0.243290200817664e19F, + 0.5109094217170944e20F, + 0.112400072777760768e22F, + 0.2585201673888497664e23F, + 0.62044840173323943936e24F, + 0.15511210043330985984e26F, + 0.403291461126605635584e27F, + 0.10888869450418352160768e29F, + 0.304888344611713860501504e30F, + 0.8841761993739701954543616e31F, + 0.26525285981219105863630848e33F, + 0.822283865417792281772556288e34F, + 0.26313083693369353016721801216e36F, + 0.868331761881188649551819440128e37F, + 0.29523279903960414084761860964352e39F, + }}; + + return factorials[i]; +} + +template <> +struct max_factorial +{ + BOOST_STATIC_CONSTANT(unsigned, value = 34); +}; + + +template <> +inline long double unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(long double)) +{ + static const boost::array factorials = {{ + 1L, + 1L, + 2L, + 6L, + 24L, + 120L, + 720L, + 5040L, + 40320L, + 362880.0L, + 3628800.0L, + 39916800.0L, + 479001600.0L, + 6227020800.0L, + 87178291200.0L, + 1307674368000.0L, + 20922789888000.0L, + 355687428096000.0L, + 6402373705728000.0L, + 121645100408832000.0L, + 0.243290200817664e19L, + 0.5109094217170944e20L, + 0.112400072777760768e22L, + 0.2585201673888497664e23L, + 0.62044840173323943936e24L, + 0.15511210043330985984e26L, + 0.403291461126605635584e27L, + 0.10888869450418352160768e29L, + 0.304888344611713860501504e30L, + 0.8841761993739701954543616e31L, + 0.26525285981219105863630848e33L, + 0.822283865417792281772556288e34L, + 0.26313083693369353016721801216e36L, + 0.868331761881188649551819440128e37L, + 0.29523279903960414084761860964352e39L, + 0.103331479663861449296666513375232e41L, + 0.3719933267899012174679994481508352e42L, + 0.137637530912263450463159795815809024e44L, + 0.5230226174666011117600072241000742912e45L, + 0.203978820811974433586402817399028973568e47L, + 0.815915283247897734345611269596115894272e48L, + 0.3345252661316380710817006205344075166515e50L, + 0.1405006117752879898543142606244511569936e52L, + 0.6041526306337383563735513206851399750726e53L, + 0.265827157478844876804362581101461589032e55L, + 0.1196222208654801945619631614956577150644e57L, + 0.5502622159812088949850305428800254892962e58L, + 0.2586232415111681806429643551536119799692e60L, + 0.1241391559253607267086228904737337503852e62L, + 0.6082818640342675608722521633212953768876e63L, + 0.3041409320171337804361260816606476884438e65L, + 0.1551118753287382280224243016469303211063e67L, + 0.8065817517094387857166063685640376697529e68L, + 0.427488328406002556429801375338939964969e70L, + 0.2308436973392413804720927426830275810833e72L, + 0.1269640335365827592596510084756651695958e74L, + 0.7109985878048634518540456474637249497365e75L, + 0.4052691950487721675568060190543232213498e77L, + 0.2350561331282878571829474910515074683829e79L, + 0.1386831185456898357379390197203894063459e81L, + 0.8320987112741390144276341183223364380754e82L, + 0.507580213877224798800856812176625227226e84L, + 0.3146997326038793752565312235495076408801e86L, + 0.1982608315404440064116146708361898137545e88L, + 0.1268869321858841641034333893351614808029e90L, + 0.8247650592082470666723170306785496252186e91L, + 0.5443449390774430640037292402478427526443e93L, + 0.3647111091818868528824985909660546442717e95L, + 0.2480035542436830599600990418569171581047e97L, + 0.1711224524281413113724683388812728390923e99L, + 0.1197857166996989179607278372168909873646e101L, + 0.8504785885678623175211676442399260102886e102L, + 0.6123445837688608686152407038527467274078e104L, + 0.4470115461512684340891257138125051110077e106L, + 0.3307885441519386412259530282212537821457e108L, + 0.2480914081139539809194647711659403366093e110L, + 0.188549470166605025498793226086114655823e112L, + 0.1451830920282858696340707840863082849837e114L, + 0.1132428117820629783145752115873204622873e116L, + 0.8946182130782975286851441715398316520698e117L, + 0.7156945704626380229481153372318653216558e119L, + 0.5797126020747367985879734231578109105412e121L, + 0.4753643337012841748421382069894049466438e123L, + 0.3945523969720658651189747118012061057144e125L, + 0.3314240134565353266999387579130131288001e127L, + 0.2817104114380550276949479442260611594801e129L, + 0.2422709538367273238176552320344125971528e131L, + 0.210775729837952771721360051869938959523e133L, + 0.1854826422573984391147968456455462843802e135L, + 0.1650795516090846108121691926245361930984e137L, + 0.1485715964481761497309522733620825737886e139L, + 0.1352001527678402962551665687594951421476e141L, + 0.1243841405464130725547532432587355307758e143L, + 0.1156772507081641574759205162306240436215e145L, + 0.1087366156656743080273652852567866010042e147L, + 0.103299784882390592625997020993947270954e149L, + 0.9916779348709496892095714015418938011582e150L, + 0.9619275968248211985332842594956369871234e152L, + 0.942689044888324774562618574305724247381e154L, + 0.9332621544394415268169923885626670049072e156L, + 0.9332621544394415268169923885626670049072e158L, + 0.9425947759838359420851623124482936749562e160L, + 0.9614466715035126609268655586972595484554e162L, + 0.990290071648618040754671525458177334909e164L, + 0.1029901674514562762384858386476504428305e167L, + 0.1081396758240290900504101305800329649721e169L, + 0.1146280563734708354534347384148349428704e171L, + 0.1226520203196137939351751701038733888713e173L, + 0.132464181945182897449989183712183259981e175L, + 0.1443859583202493582204882102462797533793e177L, + 0.1588245541522742940425370312709077287172e179L, + 0.1762952551090244663872161047107075788761e181L, + 0.1974506857221074023536820372759924883413e183L, + 0.2231192748659813646596607021218715118256e185L, + 0.2543559733472187557120132004189335234812e187L, + 0.2925093693493015690688151804817735520034e189L, + 0.339310868445189820119825609358857320324e191L, + 0.396993716080872089540195962949863064779e193L, + 0.4684525849754290656574312362808384164393e195L, + 0.5574585761207605881323431711741977155627e197L, + 0.6689502913449127057588118054090372586753e199L, + 0.8094298525273443739681622845449350829971e201L, + 0.9875044200833601362411579871448208012564e203L, + 0.1214630436702532967576624324188129585545e206L, + 0.1506141741511140879795014161993280686076e208L, + 0.1882677176888926099743767702491600857595e210L, + 0.237217324288004688567714730513941708057e212L, + 0.3012660018457659544809977077527059692324e214L, + 0.3856204823625804217356770659234636406175e216L, + 0.4974504222477287440390234150412680963966e218L, + 0.6466855489220473672507304395536485253155e220L, + 0.8471580690878820510984568758152795681634e222L, + 0.1118248651196004307449963076076169029976e225L, + 0.1487270706090685728908450891181304809868e227L, + 0.1992942746161518876737324194182948445223e229L, + 0.269047270731805048359538766214698040105e231L, + 0.3659042881952548657689727220519893345429e233L, + 0.5012888748274991661034926292112253883237e235L, + 0.6917786472619488492228198283114910358867e237L, + 0.9615723196941089004197195613529725398826e239L, + 0.1346201247571752460587607385894161555836e242L, + 0.1898143759076170969428526414110767793728e244L, + 0.2695364137888162776588507508037290267094e246L, + 0.3854370717180072770521565736493325081944e248L, + 0.5550293832739304789551054660550388118e250L, + 0.80479260574719919448490292577980627711e252L, + 0.1174997204390910823947958271638517164581e255L, + 0.1727245890454638911203498659308620231933e257L, + 0.2556323917872865588581178015776757943262e259L, + 0.380892263763056972698595524350736933546e261L, + 0.571338395644585459047893286526105400319e263L, + 0.8627209774233240431623188626544191544816e265L, + 0.1311335885683452545606724671234717114812e268L, + 0.2006343905095682394778288746989117185662e270L, + 0.308976961384735088795856467036324046592e272L, + 0.4789142901463393876335775239063022722176e274L, + 0.7471062926282894447083809372938315446595e276L, + 0.1172956879426414428192158071551315525115e279L, + 0.1853271869493734796543609753051078529682e281L, + 0.2946702272495038326504339507351214862195e283L, + 0.4714723635992061322406943211761943779512e285L, + 0.7590705053947218729075178570936729485014e287L, + 0.1229694218739449434110178928491750176572e290L, + 0.2004401576545302577599591653441552787813e292L, + 0.3287218585534296227263330311644146572013e294L, + 0.5423910666131588774984495014212841843822e296L, + 0.9003691705778437366474261723593317460744e298L, + 0.1503616514864999040201201707840084015944e301L, + 0.2526075744973198387538018869171341146786e303L, + 0.4269068009004705274939251888899566538069e305L, + 0.7257415615307998967396728211129263114717e307L, + }}; + + return factorials[i]; +} + +template <> +struct max_factorial +{ + BOOST_STATIC_CONSTANT(unsigned, value = 170); +}; + +template <> +inline double unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(double)) +{ + return static_cast(boost::math::unchecked_factorial(i)); +} + +template <> +struct max_factorial +{ + BOOST_STATIC_CONSTANT(unsigned, + value = ::boost::math::max_factorial::value); +}; + +template +inline T unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) +{ + static const boost::array factorials = {{ + boost::lexical_cast("1"), + boost::lexical_cast("1"), + boost::lexical_cast("2"), + boost::lexical_cast("6"), + boost::lexical_cast("24"), + boost::lexical_cast("120"), + boost::lexical_cast("720"), + boost::lexical_cast("5040"), + boost::lexical_cast("40320"), + boost::lexical_cast("362880"), + boost::lexical_cast("3628800"), + boost::lexical_cast("39916800"), + boost::lexical_cast("479001600"), + boost::lexical_cast("6227020800"), + boost::lexical_cast("87178291200"), + boost::lexical_cast("1307674368000"), + boost::lexical_cast("20922789888000"), + boost::lexical_cast("355687428096000"), + boost::lexical_cast("6402373705728000"), + boost::lexical_cast("121645100408832000"), + boost::lexical_cast("2432902008176640000"), + boost::lexical_cast("51090942171709440000"), + boost::lexical_cast("1124000727777607680000"), + boost::lexical_cast("25852016738884976640000"), + boost::lexical_cast("620448401733239439360000"), + boost::lexical_cast("15511210043330985984000000"), + boost::lexical_cast("403291461126605635584000000"), + boost::lexical_cast("10888869450418352160768000000"), + boost::lexical_cast("304888344611713860501504000000"), + boost::lexical_cast("8841761993739701954543616000000"), + boost::lexical_cast("265252859812191058636308480000000"), + boost::lexical_cast("8222838654177922817725562880000000"), + boost::lexical_cast("263130836933693530167218012160000000"), + boost::lexical_cast("8683317618811886495518194401280000000"), + boost::lexical_cast("295232799039604140847618609643520000000"), + boost::lexical_cast("10333147966386144929666651337523200000000"), + boost::lexical_cast("371993326789901217467999448150835200000000"), + boost::lexical_cast("13763753091226345046315979581580902400000000"), + boost::lexical_cast("523022617466601111760007224100074291200000000"), + boost::lexical_cast("20397882081197443358640281739902897356800000000"), + boost::lexical_cast("815915283247897734345611269596115894272000000000"), + boost::lexical_cast("33452526613163807108170062053440751665152000000000"), + boost::lexical_cast("1405006117752879898543142606244511569936384000000000"), + boost::lexical_cast("60415263063373835637355132068513997507264512000000000"), + boost::lexical_cast("2658271574788448768043625811014615890319638528000000000"), + boost::lexical_cast("119622220865480194561963161495657715064383733760000000000"), + boost::lexical_cast("5502622159812088949850305428800254892961651752960000000000"), + boost::lexical_cast("258623241511168180642964355153611979969197632389120000000000"), + boost::lexical_cast("12413915592536072670862289047373375038521486354677760000000000"), + boost::lexical_cast("608281864034267560872252163321295376887552831379210240000000000"), + boost::lexical_cast("30414093201713378043612608166064768844377641568960512000000000000"), + boost::lexical_cast("1551118753287382280224243016469303211063259720016986112000000000000"), + boost::lexical_cast("80658175170943878571660636856403766975289505440883277824000000000000"), + boost::lexical_cast("4274883284060025564298013753389399649690343788366813724672000000000000"), + boost::lexical_cast("230843697339241380472092742683027581083278564571807941132288000000000000"), + boost::lexical_cast("12696403353658275925965100847566516959580321051449436762275840000000000000"), + boost::lexical_cast("710998587804863451854045647463724949736497978881168458687447040000000000000"), + boost::lexical_cast("40526919504877216755680601905432322134980384796226602145184481280000000000000"), + boost::lexical_cast("2350561331282878571829474910515074683828862318181142924420699914240000000000000"), + boost::lexical_cast("138683118545689835737939019720389406345902876772687432540821294940160000000000000"), + boost::lexical_cast("8320987112741390144276341183223364380754172606361245952449277696409600000000000000"), + boost::lexical_cast("507580213877224798800856812176625227226004528988036003099405939480985600000000000000"), + boost::lexical_cast("31469973260387937525653122354950764088012280797258232192163168247821107200000000000000"), + boost::lexical_cast("1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000"), + boost::lexical_cast("126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000"), + boost::lexical_cast("8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000"), + boost::lexical_cast("544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000"), + boost::lexical_cast("36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000"), + boost::lexical_cast("2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000"), + boost::lexical_cast("171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000"), + boost::lexical_cast("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000"), + boost::lexical_cast("850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000"), + boost::lexical_cast("61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000"), + boost::lexical_cast("4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000"), + boost::lexical_cast("330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000"), + boost::lexical_cast("24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000"), + boost::lexical_cast("1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000"), + boost::lexical_cast("145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000"), + boost::lexical_cast("11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000"), + boost::lexical_cast("894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000"), + boost::lexical_cast("71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000"), + boost::lexical_cast("5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000"), + boost::lexical_cast("475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000"), + boost::lexical_cast("39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000"), + boost::lexical_cast("3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000"), + boost::lexical_cast("281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000"), + boost::lexical_cast("24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000"), + boost::lexical_cast("2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000"), + boost::lexical_cast("185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000"), + boost::lexical_cast("16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000"), + boost::lexical_cast("1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000"), + boost::lexical_cast("135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000"), + boost::lexical_cast("12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000"), + boost::lexical_cast("1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000"), + boost::lexical_cast("108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000"), + boost::lexical_cast("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000"), + boost::lexical_cast("991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000"), + boost::lexical_cast("96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000"), + boost::lexical_cast("9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000"), + boost::lexical_cast("933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"), + boost::lexical_cast("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"), + }}; + + return factorials[i]; +} + +template +struct max_factorial +{ + BOOST_STATIC_CONSTANT(unsigned, value = 100); +}; + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SP_UC_FACTORIALS_HPP diff --git a/include/boost/math/special_functions/digamma.hpp b/include/boost/math/special_functions/digamma.hpp new file mode 100644 index 000000000..12946cec7 --- /dev/null +++ b/include/boost/math/special_functions/digamma.hpp @@ -0,0 +1,445 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_DIGAMMA_HPP +#define BOOST_MATH_SF_DIGAMMA_HPP + +#include +#include +#include +#include +#include + +namespace boost{ +namespace math{ +namespace detail{ +// +// Begin by defining the smallest value for which it is safe to +// use the asymptotic expansion for digamma: +// +inline unsigned digamma_large_lim(const mpl::int_<0>*) +{ return 20; } + +inline unsigned digamma_large_lim(const void*) +{ return 10; } +// +// Implementations of the asymptotic expansion come next, +// the coefficients of the series have been evaluated +// in advance at high precision, and the series truncated +// at the first term that's too small to effect the result. +// Note that the series becomes divergent after a while +// so truncation is very important. +// +// This first one gives 34-digit precision for x >= 20: +// +template +inline T digamma_imp_large(T x, const mpl::int_<0>*) +{ + BOOST_MATH_STD_USING // ADL of std functions. + static const T P[] = { + 0.083333333333333333333333333333333333333333333333333L, + -0.0083333333333333333333333333333333333333333333333333L, + 0.003968253968253968253968253968253968253968253968254L, + -0.0041666666666666666666666666666666666666666666666667L, + 0.0075757575757575757575757575757575757575757575757576L, + -0.021092796092796092796092796092796092796092796092796L, + 0.083333333333333333333333333333333333333333333333333L, + -0.44325980392156862745098039215686274509803921568627L, + 3.0539543302701197438039543302701197438039543302701L, + -26.456212121212121212121212121212121212121212121212L, + 281.4601449275362318840579710144927536231884057971L, + -3607.510546398046398046398046398046398046398046398L, + 54827.583333333333333333333333333333333333333333333L, + -974936.82385057471264367816091954022988505747126437L, + 20052695.796688078946143462272494530559046688078946L, + -472384867.72162990196078431372549019607843137254902L, + 12635724795.916666666666666666666666666666666666667L + }; + x -= 1; + T result = log(x); + result += 1 / (2 * x); + T z = 1 / (x*x); + result -= z * tools::evaluate_polynomial(P, z); + return result; +} +// +// 19-digit precision for x >= 10: +// +template +inline T digamma_imp_large(T x, const mpl::int_<64>*) +{ + BOOST_MATH_STD_USING // ADL of std functions. + static const T P[] = { + 0.083333333333333333333333333333333333333333333333333L, + -0.0083333333333333333333333333333333333333333333333333L, + 0.003968253968253968253968253968253968253968253968254L, + -0.0041666666666666666666666666666666666666666666666667L, + 0.0075757575757575757575757575757575757575757575757576L, + -0.021092796092796092796092796092796092796092796092796L, + 0.083333333333333333333333333333333333333333333333333L, + -0.44325980392156862745098039215686274509803921568627L, + 3.0539543302701197438039543302701197438039543302701L, + -26.456212121212121212121212121212121212121212121212L, + 281.4601449275362318840579710144927536231884057971L, + }; + x -= 1; + T result = log(x); + result += 1 / (2 * x); + T z = 1 / (x*x); + result -= z * tools::evaluate_polynomial(P, z); + return result; +} +// +// 17-digit precision for x >= 10: +// +template +inline T digamma_imp_large(T x, const mpl::int_<53>*) +{ + BOOST_MATH_STD_USING // ADL of std functions. + static const T P[] = { + 0.083333333333333333333333333333333333333333333333333L, + -0.0083333333333333333333333333333333333333333333333333L, + 0.003968253968253968253968253968253968253968253968254L, + -0.0041666666666666666666666666666666666666666666666667L, + 0.0075757575757575757575757575757575757575757575757576L, + -0.021092796092796092796092796092796092796092796092796L, + 0.083333333333333333333333333333333333333333333333333L, + -0.44325980392156862745098039215686274509803921568627L + }; + x -= 1; + T result = log(x); + result += 1 / (2 * x); + T z = 1 / (x*x); + result -= z * tools::evaluate_polynomial(P, z); + return result; +} +// +// 9-digit precision for x >= 10: +// +template +inline T digamma_imp_large(T x, const mpl::int_<24>*) +{ + BOOST_MATH_STD_USING // ADL of std functions. + static const T P[] = { + 0.083333333333333333333333333333333333333333333333333L, + -0.0083333333333333333333333333333333333333333333333333L, + 0.003968253968253968253968253968253968253968253968254L + }; + x -= 1; + T result = log(x); + result += 1 / (2 * x); + T z = 1 / (x*x); + result -= z * tools::evaluate_polynomial(P, z); + return result; +} +// +// Now follow rational approximations over the range [1,2]. +// +// 35-digit precision: +// +template +T digamma_imp_1_2(T x, const mpl::int_<0>*) +{ + // + // Now the approximation, we use the form: + // + // digamma(x) = (x - root) * (Y + R(x-1)) + // + // Where root is the location of the positive root of digamma, + // Y is a constant, and R is optimised for low absolute error + // compared to Y. + // + // Max error found at 128-bit long double precision: 5.541e-35 + // Maximum Deviation Found (approximation error): 1.965e-35 + // + static const float Y = 0.99558162689208984375F; + + static const T root1 = 1569415565.0 / 1073741824uL; + static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL; + static const T root3 = ((111616537.0 / 1073741824uL) / 1073741824uL) / 1073741824uL; + static const T root4 = (((503992070.0 / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL; + static const T root5 = 0.52112228569249997894452490385577338504019838794544e-36L; + + static const T P[] = { + 0.25479851061131551526977464225335883769L, + -0.18684290534374944114622235683619897417L, + -0.80360876047931768958995775910991929922L, + -0.67227342794829064330498117008564270136L, + -0.26569010991230617151285010695543858005L, + -0.05775672694575986971640757748003553385L, + -0.0071432147823164975485922555833274240665L, + -0.00048740753910766168912364555706064993274L, + -0.16454996865214115723416538844975174761e-4L, + -0.20327832297631728077731148515093164955e-6L + }; + static const T Q[] = { + 1, + 2.6210924610812025425088411043163287646L, + 2.6850757078559596612621337395886392594L, + 1.4320913706209965531250495490639289418L, + 0.4410872083455009362557012239501953402L, + 0.081385727399251729505165509278152487225L, + 0.0089478633066857163432104815183858149496L, + 0.00055861622855066424871506755481997374154L, + 0.1760168552357342401304462967950178554e-4L, + 0.20585454493572473724556649516040874384e-6L, + -0.90745971844439990284514121823069162795e-11L, + 0.48857673606545846774761343500033283272e-13L, + }; + T g = x - root1; + g -= root2; + g -= root3; + g -= root4; + g -= root5; + T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1); + T result = g * Y + g * r; + + return result; +} +// +// 19-digit precision: +// +template +T digamma_imp_1_2(T x, const mpl::int_<64>*) +{ + // + // Now the approximation, we use the form: + // + // digamma(x) = (x - root) * (Y + R(x-1)) + // + // Where root is the location of the positive root of digamma, + // Y is a constant, and R is optimised for low absolute error + // compared to Y. + // + // Max error found at 80-bit long double precision: 5.016e-20 + // Maximum Deviation Found (approximation error): 3.575e-20 + // + static const float Y = 0.99558162689208984375F; + + static const T root1 = 1569415565.0 / 1073741824uL; + static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL; + static const T root3 = 0.9016312093258695918615325266959189453125e-19L; + + static const T P[] = { + 0.254798510611315515235L, + -0.314628554532916496608L, + -0.665836341559876230295L, + -0.314767657147375752913L, + -0.0541156266153505273939L, + -0.00289268368333918761452L + }; + static const T Q[] = { + 1, + 2.1195759927055347547L, + 1.54350554664961128724L, + 0.486986018231042975162L, + 0.0660481487173569812846L, + 0.00298999662592323990972L, + -0.165079794012604905639e-5L, + 0.317940243105952177571e-7L + }; + T g = x - root1; + g -= root2; + g -= root3; + T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1); + T result = g * Y + g * r; + + return result; +} +// +// 18-digit precision: +// +template +T digamma_imp_1_2(T x, const mpl::int_<53>*) +{ + // + // Now the approximation, we use the form: + // + // digamma(x) = (x - root) * (Y + R(x-1)) + // + // Where root is the location of the positive root of digamma, + // Y is a constant, and R is optimised for low absolute error + // compared to Y. + // + // Maximum Deviation Found: 1.466e-18 + // At double precision, max error found: 2.452e-17 + // + static const float Y = 0.99558162689208984F; + + static const T root1 = 1569415565.0 / 1073741824uL; + static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL; + static const T root3 = 0.9016312093258695918615325266959189453125e-19L; + + static const T P[] = { + 0.25479851061131551L, + -0.32555031186804491L, + -0.65031853770896507L, + -0.28919126444774784L, + -0.045251321448739056L, + -0.0020713321167745952L + }; + static const T Q[] = { + 1L, + 2.0767117023730469L, + 1.4606242909763515L, + 0.43593529692665969L, + 0.054151797245674225L, + 0.0021284987017821144L, + -0.55789841321675513e-6L + }; + T g = x - root1; + g -= root2; + g -= root3; + T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1); + T result = g * Y + g * r; + + return result; +} +// +// 9-digit precision: +// +template +inline T digamma_imp_1_2(T x, const mpl::int_<24>*) +{ + // + // Now the approximation, we use the form: + // + // digamma(x) = (x - root) * (Y + R(x-1)) + // + // Where root is the location of the positive root of digamma, + // Y is a constant, and R is optimised for low absolute error + // compared to Y. + // + // Maximum Deviation Found: 3.388e-010 + // At float precision, max error found: 2.008725e-008 + // + static const float Y = 0.99558162689208984f; + static const T root = 1532632.0f / 1048576; + static const T root_minor = static_cast(0.3700660185912626595423257213284682051735604e-6L); + static const T P[] = { + 0.25479851023250261e0, + -0.44981331915268368e0, + -0.43916936919946835e0, + -0.61041765350579073e-1 + }; + static const T Q[] = { + 0.1e1, + 0.15890202430554952e1, + 0.65341249856146947e0, + 0.63851690523355715e-1 + }; + T g = x - root; + g -= root_minor; + T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1); + T result = g * Y + g * r; + + return result; +} + +template +T digamma_imp(T x, const Tag* t, const Policy& pol) +{ + // + // This handles reflection of negative arguments, and all our + // error handling, then forwards to the T-specific approximation. + // + BOOST_MATH_STD_USING // ADL of std functions. + + T result = 0; + // + // Check for negative arguments and use reflection: + // + if(x < 0) + { + // Reflect: + x = 1 - x; + // Argument reduction for tan: + T remainder = x - floor(x); + // Shift to negative if > 0.5: + if(remainder > 0.5) + { + remainder -= 1; + } + // + // check for evaluation at a negative pole: + // + if(remainder == 0) + { + return policies::raise_pole_error("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol); + } + result = constants::pi() / tan(constants::pi() * remainder); + } + // + // If we're above the lower-limit for the + // asymptotic expansion then use it: + // + if(x >= digamma_large_lim(t)) + { + result += digamma_imp_large(x, t); + } + else + { + // + // If x > 2 reduce to the interval [1,2]: + // + while(x > 2) + { + x -= 1; + result += 1/x; + } + // + // If x < 1 use recurrance to shift to > 1: + // + if(x < 1) + { + result = -1/x; + x += 1; + } + result += digamma_imp_1_2(x, t); + } + return result; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + digamma(T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::or_< + mpl::less_equal >, + mpl::greater > + >, + mpl::int_<0>, + typename mpl::if_< + mpl::less >, + mpl::int_<24>, + typename mpl::if_< + mpl::less >, + mpl::int_<53>, + mpl::int_<64> + >::type + >::type + >::type tag_type; + + return policies::checked_narrowing_cast(detail::digamma_imp( + static_cast(x), + static_cast(0), pol), "boost::math::digamma<%1%>(%1%)"); +} + +template +inline typename tools::promote_args::type + digamma(T x) +{ + return digamma(x, policies::policy<>()); +} + +} // namespace math +} // namespace boost +#endif diff --git a/include/boost/math/special_functions/ellint_1.hpp b/include/boost/math/special_functions/ellint_1.hpp new file mode 100644 index 000000000..8b10cf044 --- /dev/null +++ b/include/boost/math/special_functions/ellint_1.hpp @@ -0,0 +1,182 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Copyright (c) 2006 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to ensure +// that the code continues to work no matter how many digits +// type T has. + +#ifndef BOOST_MATH_ELLINT_1_HPP +#define BOOST_MATH_ELLINT_1_HPP + +#include +#include +#include +#include + +// Elliptic integrals (complete and incomplete) of the first kind +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { + +template +typename tools::promote_args::type ellint_1(T1 k, T2 phi, const Policy& pol); + +namespace detail{ + +template +T ellint_k_imp(T k, const Policy& pol); + +// Elliptic integral (Legendre form) of the first kind +template +T ellint_f_imp(T phi, T k, const Policy& pol) +{ + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + static const char* function = "boost::math::ellint_f<%1%>(%1%,%1%)"; + BOOST_MATH_INSTRUMENT_VARIABLE(phi); + BOOST_MATH_INSTRUMENT_VARIABLE(k); + BOOST_MATH_INSTRUMENT_VARIABLE(function); + + if (abs(k) > 1) + { + return policies::raise_domain_error(function, + "Got k = %1%, function requires |k| <= 1", k, pol); + } + + bool invert = false; + if(phi < 0) + { + BOOST_MATH_INSTRUMENT_VARIABLE(phi); + phi = fabs(phi); + invert = true; + } + + T result; + + if(phi >= tools::max_value()) + { + // Need to handle infinity as a special case: + result = policies::raise_overflow_error(function, 0, pol); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + } + else if(phi > 1 / tools::epsilon()) + { + // Phi is so large that phi%pi is necessarily zero (or garbage), + // just return the second part of the duplication formula: + result = 2 * phi * ellint_k_imp(k, pol) / constants::pi(); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + } + else + { + // Carlson's algorithm works only for |phi| <= pi/2, + // use the integrand's periodicity to normalize phi + // + // Xiaogang's original code used a cast to long long here + // but that fails if T has more digits than a long long, + // so rewritten to use fmod instead: + // + BOOST_MATH_INSTRUMENT_CODE("pi/2 = " << constants::pi() / 2); + T rphi = boost::math::tools::fmod_workaround(phi, constants::pi() / 2); + BOOST_MATH_INSTRUMENT_VARIABLE(rphi); + T m = 2 * (phi - rphi) / constants::pi(); + BOOST_MATH_INSTRUMENT_VARIABLE(m); + int s = 1; + if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5) + { + m += 1; + s = -1; + rphi = constants::pi() / 2 - rphi; + BOOST_MATH_INSTRUMENT_VARIABLE(rphi); + } + T sinp = sin(rphi); + T cosp = cos(rphi); + BOOST_MATH_INSTRUMENT_VARIABLE(sinp); + BOOST_MATH_INSTRUMENT_VARIABLE(cosp); + result = s * sinp * ellint_rf_imp(cosp * cosp, 1 - k * k * sinp * sinp, T(1), pol); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + if(m != 0) + { + result += m * ellint_k_imp(k, pol); + BOOST_MATH_INSTRUMENT_VARIABLE(result); + } + } + return invert ? -result : result; +} + +// Complete elliptic integral (Legendre form) of the first kind +template +T ellint_k_imp(T k, const Policy& pol) +{ + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_k<%1%>(%1%)"; + + if (abs(k) > 1) + { + return policies::raise_domain_error(function, + "Got k = %1%, function requires |k| <= 1", k, pol); + } + if (abs(k) == 1) + { + return policies::raise_overflow_error(function, 0, pol); + } + + T x = 0; + T y = 1 - k * k; + T z = 1; + T value = ellint_rf_imp(x, y, z, pol); + + return value; +} + +template +inline typename tools::promote_args::type ellint_1(T k, const Policy& pol, const mpl::true_&) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::ellint_k_imp(static_cast(k), pol), "boost::math::ellint_1<%1%>(%1%)"); +} + +template +inline typename tools::promote_args::type ellint_1(T1 k, T2 phi, const mpl::false_&) +{ + return boost::math::ellint_1(k, phi, policies::policy<>()); +} + +} + +// Complete elliptic integral (Legendre form) of the first kind +template +inline typename tools::promote_args::type ellint_1(T k) +{ + return ellint_1(k, policies::policy<>()); +} + +// Elliptic integral (Legendre form) of the first kind +template +inline typename tools::promote_args::type ellint_1(T1 k, T2 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::ellint_f_imp(static_cast(phi), static_cast(k), pol), "boost::math::ellint_1<%1%>(%1%,%1%)"); +} + +template +inline typename tools::promote_args::type ellint_1(T1 k, T2 phi) +{ + typedef typename policies::is_policy::type tag_type; + return detail::ellint_1(k, phi, tag_type()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_1_HPP diff --git a/include/boost/math/special_functions/ellint_2.hpp b/include/boost/math/special_functions/ellint_2.hpp new file mode 100644 index 000000000..341fd8be3 --- /dev/null +++ b/include/boost/math/special_functions/ellint_2.hpp @@ -0,0 +1,163 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Copyright (c) 2006 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to ensure +// that the code continues to work no matter how many digits +// type T has. + +#ifndef BOOST_MATH_ELLINT_2_HPP +#define BOOST_MATH_ELLINT_2_HPP + +#include +#include +#include +#include +#include + +// Elliptic integrals (complete and incomplete) of the second kind +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { + +template +typename tools::promote_args::type ellint_2(T1 k, T2 phi, const Policy& pol); + +namespace detail{ + +template +T ellint_e_imp(T k, const Policy& pol); + +// Elliptic integral (Legendre form) of the second kind +template +T ellint_e_imp(T phi, T k, const Policy& pol) +{ + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + bool invert = false; + if(phi < 0) + { + phi = fabs(phi); + invert = true; + } + + T result; + + if(phi >= tools::max_value()) + { + // Need to handle infinity as a special case: + result = policies::raise_overflow_error("boost::math::ellint_e<%1%>(%1%,%1%)", 0, pol); + } + else if(phi > 1 / tools::epsilon()) + { + // Phi is so large that phi%pi is necessarily zero (or garbage), + // just return the second part of the duplication formula: + result = 2 * phi * ellint_e_imp(k, pol) / constants::pi(); + } + else + { + // Carlson's algorithm works only for |phi| <= pi/2, + // use the integrand's periodicity to normalize phi + // + // Xiaogang's original code used a cast to long long here + // but that fails if T has more digits than a long long, + // so rewritten to use fmod instead: + // + T rphi = boost::math::tools::fmod_workaround(phi, constants::pi() / 2); + T m = 2 * (phi - rphi) / constants::pi(); + int s = 1; + if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5) + { + m += 1; + s = -1; + rphi = constants::pi() / 2 - rphi; + } + T sinp = sin(rphi); + T cosp = cos(rphi); + T x = cosp * cosp; + T t = k * k * sinp * sinp; + T y = 1 - t; + T z = 1; + result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3); + if(m != 0) + result += m * ellint_e_imp(k, pol); + } + return invert ? -result : result; +} + +// Complete elliptic integral (Legendre form) of the second kind +template +T ellint_e_imp(T k, const Policy& pol) +{ + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + if (abs(k) > 1) + { + return policies::raise_domain_error("boost::math::ellint_e<%1%>(%1%)", + "Got k = %1%, function requires |k| <= 1", k, pol); + } + if (abs(k) == 1) + { + return static_cast(1); + } + + T x = 0; + T t = k * k; + T y = 1 - t; + T z = 1; + T value = ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3; + + return value; +} + +template +inline typename tools::promote_args::type ellint_2(T k, const Policy& pol, const mpl::true_&) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::ellint_e_imp(static_cast(k), pol), "boost::math::ellint_2<%1%>(%1%)"); +} + +// Elliptic integral (Legendre form) of the second kind +template +inline typename tools::promote_args::type ellint_2(T1 k, T2 phi, const mpl::false_&) +{ + return boost::math::ellint_2(k, phi, policies::policy<>()); +} + +} // detail + +// Complete elliptic integral (Legendre form) of the second kind +template +inline typename tools::promote_args::type ellint_2(T k) +{ + return ellint_2(k, policies::policy<>()); +} + +// Elliptic integral (Legendre form) of the second kind +template +inline typename tools::promote_args::type ellint_2(T1 k, T2 phi) +{ + typedef typename policies::is_policy::type tag_type; + return detail::ellint_2(k, phi, tag_type()); +} + +template +inline typename tools::promote_args::type ellint_2(T1 k, T2 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::ellint_e_imp(static_cast(phi), static_cast(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)"); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_2_HPP diff --git a/include/boost/math/special_functions/ellint_3.hpp b/include/boost/math/special_functions/ellint_3.hpp new file mode 100644 index 000000000..ee5aa8359 --- /dev/null +++ b/include/boost/math/special_functions/ellint_3.hpp @@ -0,0 +1,327 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Copyright (c) 2006 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to correctly +// handle the various corner cases. +// + +#ifndef BOOST_MATH_ELLINT_3_HPP +#define BOOST_MATH_ELLINT_3_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +// Elliptic integrals (complete and incomplete) of the third kind +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { + +template +typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol); + +namespace detail{ + +template +T ellint_pi_imp(T v, T k, T vc, const Policy& pol); + +// Elliptic integral (Legendre form) of the third kind +template +T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol) +{ + // Note vc = 1-v presumably without cancellation error. + T value, x, y, z, p, t; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + using namespace boost::math::constants; + + static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)"; + + if (abs(k) > 1) + { + return policies::raise_domain_error(function, + "Got k = %1%, function requires |k| <= 1", k, pol); + } + + T sphi = sin(fabs(phi)); + + if(v > 1 / (sphi * sphi)) + { + // Complex result is a domain error: + return policies::raise_domain_error(function, + "Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol); + } + + // Special cases first: + if(v == 0) + { + // A&S 17.7.18 & 19 + return (k == 0) ? phi : ellint_f_imp(phi, k, pol); + } + if(phi == constants::pi() / 2) + { + // Have to filter this case out before the next + // special case, otherwise we might get an infinity from + // tan(phi). + // Also note that since we can't represent PI/2 exactly + // in a T, this is a bit of a guess as to the users true + // intent... + // + return ellint_pi_imp(v, k, vc, pol); + } + if(k == 0) + { + // A&S 17.7.20: + if(v < 1) + { + T vcr = sqrt(vc); + return atan(vcr * tan(phi)) / vcr; + } + else if(v == 1) + { + return tan(phi); + } + else + { + // v > 1: + T vcr = sqrt(-vc); + T arg = vcr * tan(phi); + return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr); + } + } + + if(v < 0) + { + // + // If we don't shift to 0 <= v <= 1 we get + // cancellation errors later on. Use + // A&S 17.7.15/16 to shift to v > 0: + // + T k2 = k * k; + T N = (k2 - v) / (1 - v); + T Nm1 = (1 - k2) / (1 - v); + T p2 = sqrt(-v * (k2 - v) / (1 - v)); + T delta = sqrt(1 - k2 * sphi * sphi); + T result = ellint_pi_imp(N, phi, k, Nm1, pol); + + result *= sqrt(Nm1 * (1 - k2 / N)); + result += ellint_f_imp(phi, k, pol) * k2 / p2; + result += atan((p2/2) * sin(2 * phi) / delta); + result /= sqrt((1 - v) * (1 - k2 / v)); + return result; + } +#if 0 // disabled but retained for future reference: see below. + if(v > 1) + { + // + // If v > 1 we can use the identity in A&S 17.7.7/8 + // to shift to 0 <= v <= 1. Unfortunately this + // identity appears only to function correctly when + // 0 <= phi <= pi/2, but it's when phi is outside that + // range that we really need it: That's when + // Carlson's formula fails, and what's more the periodicity + // reduction used below on phi doesn't work when v > 1. + // + // So we're stuck... the code is archived here in case + // some bright spart can figure out the fix. + // + T k2 = k * k; + T N = k2 / v; + T Nm1 = (v - k2) / v; + T p1 = sqrt((-vc) * (1 - k2 / v)); + T delta = sqrt(1 - k2 * sphi * sphi); + // + // These next two terms have a large amount of cancellation + // so it's not clear if this relation is useable even if + // the issues with phi > pi/2 can be fixed: + // + T result = -ellint_pi_imp(N, phi, k, Nm1); + result += ellint_f_imp(phi, k); + // + // This log term gives the complex result when + // n > 1/sin^2(phi) + // However that case is dealt with as an error above, + // so we should always get a real result here: + // + result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1); + return result; + } +#endif + + // Carlson's algorithm works only for |phi| <= pi/2, + // use the integrand's periodicity to normalize phi + // + // Xiaogang's original code used a cast to long long here + // but that fails if T has more digits than a long long, + // so rewritten to use fmod instead: + // + if(fabs(phi) > 1 / tools::epsilon()) + { + if(v > 1) + return policies::raise_domain_error( + function, + "Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol); + // + // Phi is so large that phi%pi is necessarily zero (or garbage), + // just return the second part of the duplication formula: + // + value = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi(); + } + else + { + T rphi = boost::math::tools::fmod_workaround(fabs(phi), constants::pi() / 2); + T m = 2 * (fabs(phi) - rphi) / constants::pi(); + int sign = 1; + if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5) + { + m += 1; + sign = -1; + rphi = constants::pi() / 2 - rphi; + } + + if((m > 0) && (v > 1)) + { + // + // The region with v > 1 and phi outside [0, pi/2] is + // currently unsupported: + // + return policies::raise_domain_error( + function, + "Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol); + } + T sinp = sin(rphi); + T cosp = cos(rphi); + x = cosp * cosp; + t = sinp * sinp; + y = 1 - k * k * t; + z = 1; + if(v * t < 0.5) + p = 1 - v * t; + else + p = x + vc * t; + value = sign * sinp * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3); + if(m > 0) + value += m * ellint_pi_imp(v, k, vc, pol); + } + + if (phi < 0) + { + value = -value; // odd function + } + return value; +} + +// Complete elliptic integral (Legendre form) of the third kind +template +T ellint_pi_imp(T v, T k, T vc, const Policy& pol) +{ + // Note arg vc = 1-v, possibly without cancellation errors + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)"; + + if (abs(k) >= 1) + { + return policies::raise_domain_error(function, + "Got k = %1%, function requires |k| <= 1", k, pol); + } + if(vc <= 0) + { + // Result is complex: + return policies::raise_domain_error(function, + "Got v = %1%, function requires v < 1", v, pol); + } + + if(v == 0) + { + return (k == 0) ? boost::math::constants::pi() / 2 : ellint_k_imp(k, pol); + } + + if(v < 0) + { + T k2 = k * k; + T N = (k2 - v) / (1 - v); + T Nm1 = (1 - k2) / (1 - v); + T p2 = sqrt(-v * (k2 - v) / (1 - v)); + + T result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol); + + result *= sqrt(Nm1 * (1 - k2 / N)); + result += ellint_k_imp(k, pol) * k2 / p2; + result /= sqrt((1 - v) * (1 - k2 / v)); + return result; + } + + T x = 0; + T y = 1 - k * k; + T z = 1; + T p = vc; + T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3; + + return value; +} + +template +inline typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi, const mpl::false_&) +{ + return boost::math::ellint_3(k, v, phi, policies::policy<>()); +} + +template +inline typename tools::promote_args::type ellint_3(T1 k, T2 v, const Policy& pol, const mpl::true_&) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_pi_imp( + static_cast(v), + static_cast(k), + static_cast(1-v), + pol), "boost::math::ellint_3<%1%>(%1%,%1%)"); +} + +} // namespace detail + +template +inline typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_pi_imp( + static_cast(v), + static_cast(phi), + static_cast(k), + static_cast(1-v), + pol), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi) +{ + typedef typename policies::is_policy::type tag_type; + return detail::ellint_3(k, v, phi, tag_type()); +} + +template +inline typename tools::promote_args::type ellint_3(T1 k, T2 v) +{ + return ellint_3(k, v, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_3_HPP diff --git a/include/boost/math/special_functions/ellint_rc.hpp b/include/boost/math/special_functions/ellint_rc.hpp new file mode 100644 index 000000000..ace2851b3 --- /dev/null +++ b/include/boost/math/special_functions/ellint_rc.hpp @@ -0,0 +1,110 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to correctly +// handle the y < 0 case. +// + +#ifndef BOOST_MATH_ELLINT_RC_HPP +#define BOOST_MATH_ELLINT_RC_HPP + +#include +#include +#include + +// Carlson's degenerate elliptic integral +// R_C(x, y) = R_F(x, y, y) = 0.5 * \int_{0}^{\infty} (t+x)^{-1/2} (t+y)^{-1} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rc_imp(T x, T y, const Policy& pol) +{ + T value, S, u, lambda, tolerance, prefix; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)"; + + if(x < 0) + { + return policies::raise_domain_error(function, + "Argument x must be non-negative but got %1%", x, pol); + } + if(y == 0) + { + return policies::raise_domain_error(function, + "Argument y must not be zero but got %1%", y, pol); + } + + // error scales as the 6th power of tolerance + tolerance = pow(4 * tools::epsilon(), T(1) / 6); + + // for y < 0, the integral is singular, return Cauchy principal value + if (y < 0) + { + prefix = sqrt(x / (x - y)); + x = x - y; + y = -y; + } + else + prefix = 1; + + // duplication: + k = 1; + do + { + u = (x + y + y) / 3; + S = y / u - 1; // 1 - x / u = 2 * S + + if (2 * abs(S) < tolerance) + break; + + T sx = sqrt(x); + T sy = sqrt(y); + lambda = 2 * sx * sy + y; + x = (x + lambda) / 4; + y = (y + lambda) / 4; + ++k; + }while(k < policies::get_max_series_iterations()); + // Check to see if we gave up too soon: + policies::check_series_iterations(function, k, pol); + + // Taylor series expansion to the 5th order + value = (1 + S * S * (T(3) / 10 + S * (T(1) / 7 + S * (T(3) / 8 + S * T(9) / 22)))) / sqrt(u); + + return value * prefix; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rc(T1 x, T2 y, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_rc_imp( + static_cast(x), + static_cast(y), pol), "boost::math::ellint_rc<%1%>(%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rc(T1 x, T2 y) +{ + return ellint_rc(x, y, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RC_HPP diff --git a/include/boost/math/special_functions/ellint_rd.hpp b/include/boost/math/special_functions/ellint_rd.hpp new file mode 100644 index 000000000..0a8f946c1 --- /dev/null +++ b/include/boost/math/special_functions/ellint_rd.hpp @@ -0,0 +1,125 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it slightly to fit into the +// Boost.Math conceptual framework better. + +#ifndef BOOST_MATH_ELLINT_RD_HPP +#define BOOST_MATH_ELLINT_RD_HPP + +#include +#include +#include + +// Carlson's elliptic integral of the second kind +// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rd_imp(T x, T y, T z, const Policy& pol) +{ + T value, u, lambda, sigma, factor, tolerance; + T X, Y, Z, EA, EB, EC, ED, EE, S1, S2; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Argument x must be >= 0, but got %1%", x, pol); + } + if (y < 0) + { + return policies::raise_domain_error(function, + "Argument y must be >= 0, but got %1%", y, pol); + } + if (z <= 0) + { + return policies::raise_domain_error(function, + "Argument z must be > 0, but got %1%", z, pol); + } + if (x + y == 0) + { + return policies::raise_domain_error(function, + "At most one argument can be zero, but got, x + y = %1%", x+y, pol); + } + + // error scales as the 6th power of tolerance + tolerance = pow(tools::epsilon() / 3, T(1)/6); + + // duplication + sigma = 0; + factor = 1; + k = 1; + do + { + u = (x + y + z + z + z) / 5; + X = (u - x) / u; + Y = (u - y) / u; + Z = (u - z) / u; + if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance) + break; + T sx = sqrt(x); + T sy = sqrt(y); + T sz = sqrt(z); + lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x); + sigma += factor / (sz * (z + lambda)); + factor /= 4; + x = (x + lambda) / 4; + y = (y + lambda) / 4; + z = (z + lambda) / 4; + ++k; + } + while(k < policies::get_max_series_iterations()); + + // Check to see if we gave up too soon: + policies::check_series_iterations(function, k, pol); + + // Taylor series expansion to the 5th order + EA = X * Y; + EB = Z * Z; + EC = EA - EB; + ED = EA - 6 * EB; + EE = ED + EC + EC; + S1 = ED * (ED * T(9) / 88 - Z * EE * T(9) / 52 - T(3) / 14); + S2 = Z * (EE / 6 + Z * (-EC * T(9) / 22 + Z * EA * T(3) / 26)); + value = 3 * sigma + factor * (1 + S1 + S2) / (u * sqrt(u)); + + return value; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_rd_imp( + static_cast(x), + static_cast(y), + static_cast(z), pol), "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z) +{ + return ellint_rd(x, y, z, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RD_HPP diff --git a/include/boost/math/special_functions/ellint_rf.hpp b/include/boost/math/special_functions/ellint_rf.hpp new file mode 100644 index 000000000..f573b21c7 --- /dev/null +++ b/include/boost/math/special_functions/ellint_rf.hpp @@ -0,0 +1,127 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to handle +// types longer than 80-bit reals. +// +#ifndef BOOST_MATH_ELLINT_RF_HPP +#define BOOST_MATH_ELLINT_RF_HPP + +#include +#include + +#include + +// Carlson's elliptic integral of the first kind +// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rf_imp(T x, T y, T z, const Policy& pol) +{ + T value, X, Y, Z, E2, E3, u, lambda, tolerance; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)"; + + if (x < 0 || y < 0 || z < 0) + { + return policies::raise_domain_error(function, + "domain error, all arguments must be non-negative, " + "only sensible result is %1%.", + std::numeric_limits::quiet_NaN(), pol); + } + if (x + y == 0 || y + z == 0 || z + x == 0) + { + return policies::raise_domain_error(function, + "domain error, at most one argument can be zero, " + "only sensible result is %1%.", + std::numeric_limits::quiet_NaN(), pol); + } + + // Carlson scales error as the 6th power of tolerance, + // but this seems not to work for types larger than + // 80-bit reals, this heuristic seems to work OK: + if(policies::digits() > 64) + { + tolerance = pow(tools::epsilon(), T(1)/4.25f); + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + } + else + { + tolerance = pow(4*tools::epsilon(), T(1)/6); + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + } + + // duplication + k = 1; + do + { + u = (x + y + z) / 3; + X = (u - x) / u; + Y = (u - y) / u; + Z = (u - z) / u; + + // Termination condition: + if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance) + break; + + T sx = sqrt(x); + T sy = sqrt(y); + T sz = sqrt(z); + lambda = sy * (sx + sz) + sz * sx; + x = (x + lambda) / 4; + y = (y + lambda) / 4; + z = (z + lambda) / 4; + ++k; + } + while(k < policies::get_max_series_iterations()); + + // Check to see if we gave up too soon: + policies::check_series_iterations(function, k, pol); + BOOST_MATH_INSTRUMENT_VARIABLE(k); + + // Taylor series expansion to the 5th order + E2 = X * Y - Z * Z; + E3 = X * Y * Z; + value = (1 + E2*(E2/24 - E3*T(3)/44 - T(0.1)) + E3/14) / sqrt(u); + BOOST_MATH_INSTRUMENT_VARIABLE(value); + + return value; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rf(T1 x, T2 y, T3 z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_rf_imp( + static_cast(x), + static_cast(y), + static_cast(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rf(T1 x, T2 y, T3 z) +{ + return ellint_rf(x, y, z, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RF_HPP diff --git a/include/boost/math/special_functions/ellint_rj.hpp b/include/boost/math/special_functions/ellint_rj.hpp new file mode 100644 index 000000000..7adc67671 --- /dev/null +++ b/include/boost/math/special_functions/ellint_rj.hpp @@ -0,0 +1,174 @@ +// Copyright (c) 2006 Xiaogang Zhang +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// History: +// XZ wrote the original of this file as part of the Google +// Summer of Code 2006. JM modified it to fit into the +// Boost.Math conceptual framework better, and to correctly +// handle the p < 0 case. +// + +#ifndef BOOST_MATH_ELLINT_RJ_HPP +#define BOOST_MATH_ELLINT_RJ_HPP + +#include +#include +#include +#include + +// Carlson's elliptic integral of the third kind +// R_J(x, y, z, p) = 1.5 * \int_{0}^{\infty} (t+p)^{-1} [(t+x)(t+y)(t+z)]^{-1/2} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol) +{ + T value, u, lambda, alpha, beta, sigma, factor, tolerance; + T X, Y, Z, P, EA, EB, EC, E2, E3, S1, S2, S3; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Argument x must be non-negative, but got x = %1%", x, pol); + } + if(y < 0) + { + return policies::raise_domain_error(function, + "Argument y must be non-negative, but got y = %1%", y, pol); + } + if(z < 0) + { + return policies::raise_domain_error(function, + "Argument z must be non-negative, but got z = %1%", z, pol); + } + if(p == 0) + { + return policies::raise_domain_error(function, + "Argument p must not be zero, but got p = %1%", p, pol); + } + if (x + y == 0 || y + z == 0 || z + x == 0) + { + return policies::raise_domain_error(function, + "At most one argument can be zero, " + "only possible result is %1%.", std::numeric_limits::quiet_NaN(), pol); + } + + // error scales as the 6th power of tolerance + tolerance = pow(T(1) * tools::epsilon() / 3, T(1) / 6); + + // for p < 0, the integral is singular, return Cauchy principal value + if (p < 0) + { + // + // We must ensure that (z - y) * (y - x) is positive. + // Since the integral is symmetrical in x, y and z + // we can just permute the values: + // + if(x > y) + std::swap(x, y); + if(y > z) + std::swap(y, z); + if(x > y) + std::swap(x, y); + + T q = -p; + T pmy = (z - y) * (y - x) / (y + q); // p - y + + BOOST_ASSERT(pmy >= 0); + + T p = pmy + y; + value = boost::math::ellint_rj(x, y, z, p, pol); + value *= pmy; + value -= 3 * boost::math::ellint_rf(x, y, z, pol); + value += 3 * sqrt((x * y * z) / (x * z + p * q)) * boost::math::ellint_rc(x * z + p * q, p * q, pol); + value /= (y + q); + return value; + } + + // duplication + sigma = 0; + factor = 1; + k = 1; + do + { + u = (x + y + z + p + p) / 5; + X = (u - x) / u; + Y = (u - y) / u; + Z = (u - z) / u; + P = (u - p) / u; + + if ((tools::max)(abs(X), abs(Y), abs(Z), abs(P)) < tolerance) + break; + + T sx = sqrt(x); + T sy = sqrt(y); + T sz = sqrt(z); + + lambda = sy * (sx + sz) + sz * sx; + alpha = p * (sx + sy + sz) + sx * sy * sz; + alpha *= alpha; + beta = p * (p + lambda) * (p + lambda); + sigma += factor * boost::math::ellint_rc(alpha, beta, pol); + factor /= 4; + x = (x + lambda) / 4; + y = (y + lambda) / 4; + z = (z + lambda) / 4; + p = (p + lambda) / 4; + ++k; + } + while(k < policies::get_max_series_iterations()); + + // Check to see if we gave up too soon: + policies::check_series_iterations(function, k, pol); + + // Taylor series expansion to the 5th order + EA = X * Y + Y * Z + Z * X; + EB = X * Y * Z; + EC = P * P; + E2 = EA - 3 * EC; + E3 = EB + 2 * P * (EA - EC); + S1 = 1 + E2 * (E2 * T(9) / 88 - E3 * T(9) / 52 - T(3) / 14); + S2 = EB * (T(1) / 6 + P * (T(-6) / 22 + P * T(3) / 26)); + S3 = P * ((EA - EC) / 3 - P * EA * T(3) / 22); + value = 3 * sigma + factor * (S1 + S2 + S3) / (u * sqrt(u)); + + return value; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_rj_imp( + static_cast(x), + static_cast(y), + static_cast(z), + static_cast(p), + pol), "boost::math::ellint_rj<%1%>(%1%,%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rj(T1 x, T2 y, T3 z, T4 p) +{ + return ellint_rj(x, y, z, p, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RJ_HPP diff --git a/include/boost/math/special_functions/erf.hpp b/include/boost/math/special_functions/erf.hpp new file mode 100644 index 000000000..3e1894dec --- /dev/null +++ b/include/boost/math/special_functions/erf.hpp @@ -0,0 +1,858 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_ERF_HPP +#define BOOST_MATH_SPECIAL_ERF_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ + +namespace detail +{ + +// +// Asymptotic series for large z: +// +template +struct erf_asympt_series_t +{ + erf_asympt_series_t(T z) : xx(2 * -z * z), tk(1) + { + BOOST_MATH_STD_USING + result = -exp(-z * z) / sqrt(boost::math::constants::pi()); + result /= z; + } + + typedef T result_type; + + T operator()() + { + BOOST_MATH_STD_USING + T r = result; + result *= tk / xx; + tk += 2; + if( fabs(r) < fabs(result)) + result = 0; + return r; + } +private: + T result; + T xx; + int tk; +}; +// +// How large z has to be in order to ensure that the series converges: +// +template +inline float erf_asymptotic_limit_N(const T&) +{ + return (std::numeric_limits::max)(); +} +inline float erf_asymptotic_limit_N(const mpl::int_<24>&) +{ + return 2.8F; +} +inline float erf_asymptotic_limit_N(const mpl::int_<53>&) +{ + return 4.3F; +} +inline float erf_asymptotic_limit_N(const mpl::int_<64>&) +{ + return 4.8F; +} +inline float erf_asymptotic_limit_N(const mpl::int_<106>&) +{ + return 6.5F; +} +inline float erf_asymptotic_limit_N(const mpl::int_<113>&) +{ + return 6.8F; +} + +template +inline T erf_asymptotic_limit() +{ + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::less_equal >, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<0>, + mpl::int_<24> + >::type, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<53>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<106>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<113>, + mpl::int_<0> + >::type + >::type + >::type + >::type + >::type tag_type; + return erf_asymptotic_limit_N(tag_type()); +} + +template +T erf_imp(T z, bool invert, const Policy& pol, const Tag& t) +{ + BOOST_MATH_STD_USING + + BOOST_MATH_INSTRUMENT_CODE("Generic erf_imp called"); + + if(z < 0) + { + if(!invert) + return -erf_imp(-z, invert, pol, t); + else + return 1 + erf_imp(-z, false, pol, t); + } + + T result; + + if(!invert && (z > detail::erf_asymptotic_limit())) + { + detail::erf_asympt_series_t s(z); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + result = boost::math::tools::sum_series(s, policies::digits(), max_iter, 1); + policies::check_series_iterations("boost::math::erf<%1%>(%1%, %1%)", max_iter, pol); + } + else + { + T x = z * z; + if(x < 0.6) + { + // Compute P: + result = z * exp(-x); + result /= sqrt(boost::math::constants::pi()); + if(result != 0) + result *= 2 * detail::lower_gamma_series(T(0.5f), x, pol); + } + else if(x < 1.1f) + { + // Compute Q: + invert = !invert; + result = tgamma_small_upper_part(T(0.5f), x, pol); + result /= sqrt(boost::math::constants::pi()); + } + else + { + // Compute Q: + invert = !invert; + result = z * exp(-x); + result /= sqrt(boost::math::constants::pi()); + result *= upper_gamma_fraction(T(0.5f), x, policies::digits()); + } + } + if(invert) + result = 1 - result; + return result; +} + +template +T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<53>& t) +{ + BOOST_MATH_STD_USING + + BOOST_MATH_INSTRUMENT_CODE("53-bit precision erf_imp called"); + + if(z < 0) + { + if(!invert) + return -erf_imp(-z, invert, pol, t); + else if(z < -0.5) + return 2 - erf_imp(-z, invert, pol, t); + else + return 1 + erf_imp(-z, false, pol, t); + } + + T result; + + // + // Big bunch of selection statements now to pick + // which implementation to use, + // try to put most likely options first: + // + if(z < 0.5) + { + // + // We're going to calculate erf: + // + if(z == 0) + { + result = T(0); + } + else if(z < 1e-10) + { + result = static_cast(z * 1.125f + z * 0.003379167095512573896158903121545171688L); + } + else + { + static const T n[7] = { 0.00337916709551257778174L, -0.000147024115786688745475L, -0.37463022236812520164L, 0.0163061594494816999803L, -0.0534354147807331748737L, 0.00161898096813581982844L, -0.0059528010489182840404L }; + static const T d[7] = { 1, -0.0435089806536379531594L, 0.442761965043509204727L, -0.017375974533016704678L, 0.0772756490303260060769L, -0.00210552465858669941879L, 0.00544772980263244037286L }; + result = static_cast(z * 1.125f + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z)); + } + } + else if((z < 14) || ((z < 28) && invert)) + { + // + // We'll be calculating erfc: + // + invert = !invert; + T r, b; + if(z < 0.75) + { + // Worst case absolute error found: 8.554649561e-018 + static const T n[5] = { -0.0361790390718262468222L, 0.301888464724047222196L, 0.201731143672633894981L, 0.0659353268087389983319L, 0.00721876720062364930761L }; + static const T d[6] = { 1, 1.58814245739127341535L, 0.99354580430196422336L, 0.291753007176902027213L, 0.033994791234913855515L, -0.000104234653166533504303L }; + static const float f0 = 0.3440242112F; + r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5); + b = f0; + } + else if(z < 1.25) + { + // Worst case absolute error found: 6.50251514e-018 + static const T n[6] = { -0.039787689261113685983L, 0.160309168830518003303L, 0.163049978514596540313L, 0.0710685660158400750009L, 0.01497188097404877543L, 0.00130080628375002584279L }; + static const T d[6] = { 1, 1.77564880074171280407L, 1.31438791181040008779L, 0.509359151038517059748L, 0.103958527905812829559L, 0.00901292460643094469406L }; + static const float f0 = 0.419990927F; + r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75); + b = f0; + } + else if(z < 2.25) + { + // Worst case absolute error found: 1.132743504e-017 + static const T n[6] = { -0.0300838560557949724172L, 0.0592886319615167248092L, 0.0622294724048409148736L, 0.0248575228109427909578L, 0.00463781847004901844581L, 0.000347305179334822548368L }; + static const T d[7] = { 1, 1.57915060645728571344L, 1.03342495188878679417L, 0.35158678814344218974L, 0.062469256580984456783L, 0.00466640448020624599948L, 0.290106403940303572448e-6L }; + static const float f0 = 0.4898625016F; + r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25); + b = f0; + } + else if(z < 3.5) + { + // Worst case absolute error found: 3.446364609e-018 + static const T n[6] = { -0.0117907570137227857015L, 0.0162667227692515660221L, 0.0175329212378413544794L, 0.00620897681269247137578L, 0.000986614895094589251706L, 0.601354618401624353425e-4L }; + static const T d[6] = { 1, 1.33374851361555383557L, 0.73227756904205983415L, 0.207410266363727673685L, 0.0304034048466731110163L, 0.00185296959991832048613L }; + static const float f0 = 0.5317370892F; + r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25); + b = f0; + } + else if(z < 5.5) + { + // Worst case absolute error found: 1.579588208e-018 + static const T n[6] = { -0.00588219091116732271979L, 0.00434428684527812140098L, 0.00466899990542371512895L, 0.00139937567253199794533L, 0.000179205902444982389766L, 0.845033527560949509345e-5L }; + static const T d[6] = { 1, 1.07389345953392962127L, 0.470965611895885060643L, 0.105594730223366124873L, 0.0121252833787344059719L, 0.000571755036133730341579L }; + static const float f0 = 0.5494099855F; + r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5); + b = f0; + } + else if(z < 9) + { + // Worst case absolute error found: 1.410768708e-017 + static const T n[5] = { -0.00273864253749621265032L, 0.0013089921066773026803L, 0.000775841526778089659703L, 0.000110909476102006410909L, 0.472577590124068298534e-5L }; + static const T d[6] = { 1, 0.650694792327863647878L, 0.161126734432670927888L, 0.0180081468446110640846L, 0.000767341359508884026192L, -0.287636719206664167616e-9L }; + static const float f0 = 0.5580308437F; + r = tools::evaluate_polynomial(n, z - 5.5) / tools::evaluate_polynomial(d, z - 5.5); + b = f0; + } + else if(z < 14) + { + // Worst case absolute error found: 1.458310511e-018 + static const T n[5] = { -0.000995856413171151859346L, 0.000320252910249376187643L, 0.000129085624923151780987L, 0.121577881306587454509e-4L, 0.33293110334156470348e-6L }; + static const T d[5] = { 1, 0.428034987547594828954L, 0.0692297359775940896439L, 0.00501515176145997560701L, 0.00013733589151338416322L }; + static const float f0 = 0.5617653728F; + r = tools::evaluate_polynomial(n, z - 9) / tools::evaluate_polynomial(d, z - 9); + b = f0; + } + else if(z < 21) + { + // Worst case absolute error found: 1.08182873e-019 + static const T n[5] = { -0.000395463268432048215535L, 0.91155953112698182321e-4L, 0.237451641259281193813e-4L, 0.145759953022524466816e-5L, 0.259395907606548998142e-7L }; + static const T d[5] = { 1, 0.281604524251560309285L, 0.0298468482900092392397L, 0.00141114575715338885136L, 0.251128951158576064819e-4L }; + static const float f0 = 0.5631566644F; + r = tools::evaluate_polynomial(n, z - 14) / tools::evaluate_polynomial(d, z - 14); + b = f0; + } + else + { + // Worst case absolute error found: 7.010370259e-018 + static const T n[4] = { -0.000139182098873874523526L, 0.395254617101737287826e-4L, 0.376801239136290345387e-5L, 0.629017242098850415839e-7L }; + static const T d[4] = { 1, 0.15077096006891495258L, 0.00756136203065884121997L, 0.000126226197336507576933L }; + static const float f0 = 0.5636912584F; + r = tools::evaluate_polynomial(n, z - 21) / tools::evaluate_polynomial(d, z - 21); + b = f0; + } + T g = exp(-z * z) / z; + result = g * b + g * r; + } + else + { + // + // Any value of z larger than 28 will underflow to zero: + // + result = 0; + invert = !invert; + } + + if(invert) + { + result = 1 - result; + } + + return result; +} // template T erf_imp(T z, bool invert, const L& l, const mpl::int_<53>& t) + + +template +T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<64>& t) +{ + BOOST_MATH_STD_USING + + BOOST_MATH_INSTRUMENT_CODE("64-bit precision erf_imp called"); + + if(z < 0) + { + if(!invert) + return -erf_imp(-z, invert, pol, t); + else if(z < -0.5) + return 2 - erf_imp(-z, invert, pol, t); + else + return 1 + erf_imp(-z, false, pol, t); + } + + T result; + + // + // Big bunch of selection statements now to pick which + // implementation to use, try to put most likely options + // first: + // + if(z < 0.5) + { + // + // We're going to calculate erf: + // + if(z == 0) + { + result = 0; + } + else if(z < 1e-10) + { + result = z * 1.125 + z * 0.003379167095512573896158903121545171688L; + } + else + { + // Worst case absolute error found: 6.688618532e-21 + static const T n[8] = { 0.00337916709551257388990745L, -0.00073695653048167948530905L, -0.374732337392919607868241L, 0.0817442448733587196071743L, -0.0421089319936548595203468L, 0.0070165709512095756344528L, -0.00495091255982435110337458L, 0.000871646599037922480317225L }; + static const T d[8] = { 1L, -0.218088218087924645390535L, 0.412542972725442099083918L, -0.0841891147873106755410271L, 0.0655338856400241519690695L, -0.0120019604454941768171266L, 0.00408165558926174048329689L, -0.000615900721557769691924509L }; + result = z * 1.125 + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z); + } + } + else if((z < 110) || ((z < 110) && invert)) // TODO FIXME!!! + { + // + // We'll be calculating erfc: + // + invert = !invert; + T r, b; + if(z < 0.75) + { + // Worst case absolute error found: 5.582813374e-21 + static const T n[6] = { -0.0361790390718262471360258L, 0.292251883444882683221149L, 0.281447041797604512774415L, 0.125610208862766947294894L, 0.0274135028268930549240776L, 0.00250839672168065762786937L }; + static const T d[6] = { 1L, 1.8545005897903486499845L, 1.43575803037831418074962L, 0.582827658753036572454135L, 0.124810476932949746447682L, 0.0113724176546353285778481L }; + static const float f0 = 0.3440242112F; + r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5); + b = f0; + } + else if(z < 1.25) + { + // Worst case absolute error found: 4.01854729e-21 + static const T n[7] = { -0.0397876892611136856954425L, 0.153165212467878293257683L, 0.191260295600936245503129L, 0.10276327061989304213645L, 0.029637090615738836726027L, 0.0046093486780275489468812L, 0.000307607820348680180548455L }; + static const T d[7] = { 1L, 1.95520072987627704987886L, 1.64762317199384860109595L, 0.768238607022126250082483L, 0.209793185936509782784315L, 0.0319569316899913392596356L, 0.00213363160895785378615014L }; + static const float f0 = 0.419990927F; + r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75); + b = f0; + } + else if(z < 2.25) + { + // Worst case absolute error found: 2.866005373e-21 + static const T n[7] = { -0.0300838560557949717328341L, 0.0538578829844454508530552L, 0.0726211541651914182692959L, 0.0367628469888049348429018L, 0.00964629015572527529605267L, 0.00133453480075291076745275L, 0.778087599782504251917881e-4L }; + static const T d[8] = { 1L, 1.75967098147167528287343L, 1.32883571437961120556307L, 0.552528596508757581287907L, 0.133793056941332861912279L, 0.0179509645176280768640766L, 0.00104712440019937356634038L, -0.106640381820357337177643e-7L }; + static const float f0 = 0.4898625016F; + r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25); + b = f0; + } + else if(z < 3.5) + { + // Worst case absolute error found: 1.045355789e-21 + static const T n[7] = { -0.0117907570137227847827732L, 0.014262132090538809896674L, 0.0202234435902960820020765L, 0.00930668299990432009042239L, 0.00213357802422065994322516L, 0.00025022987386460102395382L, 0.120534912219588189822126e-4L }; + static const T d[7] = { 1L, 1.50376225203620482047419L, 0.965397786204462896346934L, 0.339265230476796681555511L, 0.0689740649541569716897427L, 0.00771060262491768307365526L, 0.000371421101531069302990367L }; + static const float f0 = 0.5317370892F; + r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25); + b = f0; + } + else if(z < 5.25) + { + // Worst case absolute error found: 8.300028706e-22 + static const T n[7] = { -0.00546954795538729307482955L, 0.00404190278731707110245394L, 0.0054963369553161170521356L, 0.00212616472603945399437862L, 0.000394984014495083900689956L, 0.365565477064442377259271e-4L, 0.135485897109932323253786e-5L }; + static const T d[8] = { 1L, 1.21019697773630784832251L, 0.620914668221143886601045L, 0.173038430661142762569515L, 0.0276550813773432047594539L, 0.00240625974424309709745382L, 0.891811817251336577241006e-4L, -0.465528836283382684461025e-11L }; + static const float f0 = 0.5489973426F; + r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5); + b = f0; + } + else if(z < 8) + { + // Worst case absolute error found: 1.700157534e-21 + static const T n[6] = { -0.00270722535905778347999196L, 0.0013187563425029400461378L, 0.00119925933261002333923989L, 0.00027849619811344664248235L, 0.267822988218331849989363e-4L, 0.923043672315028197865066e-6L }; + static const T d[7] = { 1L, 0.814632808543141591118279L, 0.268901665856299542168425L, 0.0449877216103041118694989L, 0.00381759663320248459168994L, 0.000131571897888596914350697L, 0.404815359675764138445257e-11L }; + static const float f0 = 0.5571740866F; + r = tools::evaluate_polynomial(n, z - 5.25) / tools::evaluate_polynomial(d, z - 5.25); + b = f0; + } + else if(z < 11.5) + { + //Worst case absolute error found: 3.002278011e-22 + static const T n[6] = { -0.00109946720691742196814323L, 0.000406425442750422675169153L, 0.000274499489416900707787024L, 0.465293770646659383436343e-4L, 0.320955425395767463401993e-5L, 0.778286018145020892261936e-7L }; + static const T d[6] = { 1L, 0.588173710611846046373373L, 0.139363331289409746077541L, 0.0166329340417083678763028L, 0.00100023921310234908642639L, 0.24254837521587225125068e-4L }; + static const float f0 = 0.5609807968F; + r = tools::evaluate_polynomial(n, z - 8) / tools::evaluate_polynomial(d, z - 8); + b = f0; + } + else if(z < 17) + { + //Worst case absolute error found: 6.741114695e-21 + static const T n[5] = { -0.00056907993601094962855594L, 0.000169498540373762264416984L, 0.518472354581100890120501e-4L, 0.382819312231928859704678e-5L, 0.824989931281894431781794e-7L }; + static const T d[6] = { 1L, 0.339637250051139347430323L, 0.043472647870310663055044L, 0.00248549335224637114641629L, 0.535633305337152900549536e-4L, -0.117490944405459578783846e-12L }; + static const float f0 = 0.5626493692F; + r = tools::evaluate_polynomial(n, z - 11.5) / tools::evaluate_polynomial(d, z - 11.5); + b = f0; + } + else if(z < 24) + { + // Worst case absolute error found: 7.802346984e-22 + static const T n[5] = { -0.000241313599483991337479091L, 0.574224975202501512365975e-4L, 0.115998962927383778460557e-4L, 0.581762134402593739370875e-6L, 0.853971555085673614607418e-8L }; + static const T d[5] = { 1L, 0.233044138299687841018015L, 0.0204186940546440312625597L, 0.000797185647564398289151125L, 0.117019281670172327758019e-4L }; + static const float f0 = 0.5634598136F; + r = tools::evaluate_polynomial(n, z - 17) / tools::evaluate_polynomial(d, z - 17); + b = f0; + } + else if(z < 38) + { + // Worst case absolute error found: 2.414228989e-22 + static const T n[5] = { -0.000146674699277760365803642L, 0.162666552112280519955647e-4L, 0.269116248509165239294897e-5L, 0.979584479468091935086972e-7L, 0.101994647625723465722285e-8L }; + static const T d[5] = { 1L, 0.165907812944847226546036L, 0.0103361716191505884359634L, 0.000286593026373868366935721L, 0.298401570840900340874568e-5L }; + static const float f0 = 0.5638477802F; + r = tools::evaluate_polynomial(n, z - 24) / tools::evaluate_polynomial(d, z - 24); + b = f0; + } + else if(z < 60) + { + // Worst case absolute error found: 5.896543869e-24 + static const T n[5] = { -0.583905797629771786720406e-4L, 0.412510325105496173512992e-5L, 0.431790922420250949096906e-6L, 0.993365155590013193345569e-8L, 0.653480510020104699270084e-10L }; + static const T d[5] = { 1L, 0.105077086072039915406159L, 0.00414278428675475620830226L, 0.726338754644523769144108e-4L, 0.477818471047398785369849e-6L }; + static const float f0 = 0.5640528202F; + r = tools::evaluate_polynomial(n, z - 38) / tools::evaluate_polynomial(d, z - 38); + b = f0; + } + else if(z < 85) + { + // Worst case absolute error found: 3.080612264e-21 + static const T n[4] = { -0.196457797609229579459841e-4L, 0.157243887666800692441195e-5L, 0.543902511192700878690335e-7L, 0.317472492369117710852685e-9L }; + static const T d[5] = { 1L, 0.052803989240957632204885L, 0.000926876069151753290378112L, 0.541011723226630257077328e-5L, 0.535093845803642394908747e-15L }; + static const float f0 = 0.5641309023F; + r = tools::evaluate_polynomial(n, z - 60) / tools::evaluate_polynomial(d, z - 60); + b = f0; + } + else + { + // Worst case absolute error found: 8.094633491e-22 + static const T n[4] = { -0.789224703978722689089794e-5L, 0.622088451660986955124162e-6L, 0.145728445676882396797184e-7L, 0.603715505542715364529243e-10L }; + static const T d[4] = { 1L, 0.0375328846356293715248719L, 0.000467919535974625308126054L, 0.193847039275845656900547e-5L }; + static const float f0 = 0.5641584396F; + r = tools::evaluate_polynomial(n, z - 85) / tools::evaluate_polynomial(d, z - 85); + b = f0; + } + T g = exp(-z * z) / z; + result = g * b + g * r; + BOOST_MATH_INSTRUMENT_CODE("r = " << r); + BOOST_MATH_INSTRUMENT_CODE("b = " << b); + BOOST_MATH_INSTRUMENT_CODE("g = " << g); + } + else + { + // + // Any value of z larger than 28 will underflow to zero: + // + result = 0; + invert = !invert; + } + + if(invert) + { + result = 1 - result; + } + + return result; +} // template T erf_imp(T z, bool invert, const L& l, const mpl::int_<64>& t) + + +template +T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<113>& t) +{ + BOOST_MATH_STD_USING + + BOOST_MATH_INSTRUMENT_CODE("113-bit precision erf_imp called"); + + if(z < 0) + { + if(!invert) + return -erf_imp(-z, invert, pol, t); + else if(z < -0.5) + return 2 - erf_imp(-z, invert, pol, t); + else + return 1 + erf_imp(-z, false, pol, t); + } + + T result; + + // + // Big bunch of selection statements now to pick which + // implementation to use, try to put most likely options + // first: + // + if(z < 0.5) + { + // + // We're going to calculate erf: + // + if(z == 0) + { + result = 0; + } + else if(z < 1e-20) + { + result = z * 1.125 + z * 0.003379167095512573896158903121545171688L; + } + else + { + // Worst case absolute error found: 1.928180863e-35 + static const T n[13] = { 0.0033791670955125738961589031215451706772L, -0.000356604747854533671135323429762519216044L, -0.374476838669183581687167228866769133591L, 0.0395338132469809122364498388174446488042L, -0.070405473508786506375820161461872523315L, 0.00575264725772369303419496752516485264994L, -0.0122324470706306942925087773122510971344L, 0.000982833333252586078523570049842642796291L, -0.000937806155615159592441487275938040285833L, 0.485407838108763091860415874932955355755e-4L, -0.50171236926234625577876479444632561922e-4L, 0.19406068817888598455243350289053451571e-5L, -0.119351103792049576459000102632508734863e-5L }; + static const T d[13] = { 1L, -0.105530368216503232473476334993759958083L, 0.488152943026846232046726653294817930988L, -0.0470361716364117780901924633553851211874L, 0.107663671943702835026199580597519084906L, -0.00919493879447389180633447493128337242362L, 0.0138231121717229362691899919242806829805L, -0.000994048559663865788847688218108232247441L, 0.00109769834527023265969224251892094019735L, -0.600458401801636062015615549258555311545e-4L, 0.51530723974502946291624848874654212384e-4L, -0.164121264470361558910636548509486296153e-5L, 0.112643498977070218963888579607359294396e-5L }; + + result = z * 1.125 + z * tools::evaluate_rational(n, d, z); + } + } + else if((z < 9) || ((z < 110) && invert)) // TODO FIXME!! + { + // + // We'll be calculating erfc: + // + invert = !invert; + T r, b; + if(z < 0.75) + { + // Worst case absolute error found: 9.46579566e-36 + static const T n[10] = { -0.0361790390718262471349157886581290316118L, 0.268773785250238404882137450640472787307L, 0.46350995084084251624649426251701042395L, 0.368375435727102373204587584306335625665L, 0.177618123820303858190236222513516291818L, 0.0566304173556669007529719743050764079095L, 0.0121631149481817424284077180037019529004L, 0.00171397353209314111395429418066990259845L, 0.000144662387395699594624184141956722488753L, 0.559870522050008635715382724858714587198e-5L }; + static const T d[10] = { 1L, 2.50344259590701770420935329380375393716L, 2.84905597172139276093882199286535521011L, 1.93691730181297099541395314232750876411L, 0.868059574796050528229446630538462280596L, 0.266360035323208212078527036132085926692L, 0.0560555526482963925944703505114360693216L, 0.0078174400311465420803366235814673576269L, 0.000657067309046405057499687417839930873806L, 0.254293850077789079098316521097979388983e-4L }; + static const float f0 = 0.3440242112F; + r = tools::evaluate_rational(n, d, z - 0.5); + b = f0; + } + else if(z < 1.25) + { + // Worst case absolute error found: 1.222145602e-35 + static const T n[10] = { -0.03978768926111368569548863384587917014L, 0.136218360681765349252731304877153919181L, 0.252782160406474440925641829129129001834L, 0.198264231106182362320012632943145619752L, 0.0923045825293507328801206570363391760624L, 0.0281157216148097885766639832985410722743L, 0.00573041663561645197870019701493117161792L, 0.000762341440133027349203518836487137709687L, 0.60471020134417423449877859375492618899e-4L, 0.219005333943510376644902615714724932217e-5L }; + static const T d[11] = { 1L, 2.38113277319993574121349184069891082204L, 2.57380422881476860215664207822277590181L, 1.65937045609044738941173490190122101824L, 0.704055811320312044285417250966993014161L, 0.20414913933328592198279939394283925451L, 0.0405162285360227740710964820549709038107L, 0.00531638867177288975915820230980317499728L, 0.000419364368135139398723983192742319455284L, 0.151874665979234971229096136924566078234e-4L, 0.807869459506748684117962248796937508011e-11L }; + static const float f0 = 0.419990927F; + r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75); + b = f0; + } + else if(z < 2) + { + // Worst case absolute error found: 5.893842955e-36 + static const T n[11] = { -0.0255063683486569102096736247449691465143L, 0.045782379672906795594927072060091308408L, 0.113248439610400562258072020811195716817L, 0.0996016254422112410086711272219455446695L, 0.0508749250027894453228337309651895478017L, 0.0171081937013828309576540212196644542209L, 0.00395354196550210630440706013523069756354L, 0.000629022203390154585475081628606234279007L, 0.664903286194855400689101617763591823345e-4L, 0.423935693893425355108071655059640137208e-5L, 0.124304036910852727351487636048151737214e-6L }; + static const T d[11] = { 1L, 2.39207679390801118396945702674440915308L, 2.62237869972649377524874287442154430843L, 1.73645189911172997548091140085423843725L, 0.769812706091926741262865732006953282036L, 0.238986814887891859065369830215615790694L, 0.0526759147274379214313767032352419949829L, 0.00814993801398361741777997755108018659382L, 0.00084829993036396244429607826663252633817L, 0.537276435448416921594616417908288527881e-4L, 0.157537193656690184073389824392669625417e-5L }; + static const float f0 = 0.4852850139F; + r = tools::evaluate_rational(n, d, z - 1.25); + b = f0; + } + else if(z < 2.75) + { + // Worst case absolute error found: 4.024770853e-36 + static const T n[10] = { -0.0108897177067473013323228381829144739013L, 0.0202210475357865979950082670101965963435L, 0.0403242149078991892599316678797913295452L, 0.0288492313188655084113941326565482276741L, 0.0116982647742533555237861890442866083526L, 0.00301908913020213436098518520436147263177L, 0.000511140165864993121203730804407968689429L, 0.555507897975436549741754647662158917103e-4L, 0.354571088276496768574495922471690102061e-5L, 0.101789333060641482357520298518780163915e-6L }; + static const T d[11] = { 1L, 1.98184247277299581801610266575921553552L, 1.77518826058984218945272444617044495028L, 0.943934346956188464279312722940302202684L, 0.328630002685235061519039528479761588138L, 0.0777535542351039388345270792222146705189L, 0.0125143974181120800829065248546370953609L, 0.00132270605931460450441108147393979771563L, 0.834118048375722123506409257130329786209e-4L, 0.239456257167492104073765911366304033453e-5L, 0.197067742893785800814802969598122120027e-13L }; + static const float f0 = 0.5216810703F; + r = tools::evaluate_polynomial(n, z - 2) / tools::evaluate_polynomial(d, z - 2); + b = f0; + } + else if(z < 3.75) + { + // Worst case absolute error found: 2.119317982e-36 + static const T n[10] = { -0.00669534469911386821762042893742722704704L, 0.00779239067529714323524154862288379264056L, 0.0167670669587476509267036865033136655094L, 0.0113887916348251443051357686146040093464L, 0.00426976750247047946700539147728477144579L, 0.00100469100574064832665606356894416652764L, 0.000153533145320881108157829902752192859922L, 0.149337551064665413462766906201269176262e-4L, 0.846377837919513024118176704010972579138e-6L, 0.214045773545256889299689737489755489478e-7L }; + static const T d[11] = { 1L, 1.78724215851193637544287795626580411105L, 1.44052576962222794702178612920219772782L, 0.687639905608366315245841860669607532265L, 0.214374367225822611754443822822738563207L, 0.0452948320968245754796139856381504201504L, 0.00649108394178118005887118777181540680812L, 0.000608904720665003139414993591868256489088L, 0.33959064390570911588709483563995284603e-4L, 0.858811916085393051026834431509997486704e-6L, 0.618878592093890510233502654703683447468e-15L }; + static const float f0 = 0.5392661095F; + r = tools::evaluate_polynomial(n, z - 2.75) / tools::evaluate_polynomial(d, z - 2.75); + b = f0; + } + else if(z < 5) + { + // Worst case absolute error found: 3.131502824e-36 + static const T n[10] = { -0.00378088626017041998499190989910098718437L, 0.0029008905292996011997575492874095588328L, 0.00662431938391549599757244232386689480515L, 0.00417809740399798845564363621020984935218L, 0.00142019749135652688012034919213168974543L, 0.000299107980170253223293530710056814995102L, 0.405161538841561396150507786831930770839e-4L, 0.346344371670880861875666253626975779945e-5L, 0.171091054330494778613793054233437928605e-6L, 0.373924433717749484258186454458704819755e-8L }; + static const T d[10] = { 1L, 1.5810750672399887547849540367499389454L, 1.12479852885403050655678225945856872694L, 0.47277272679268851560291322980574597267L, 0.129444913616967588584693095240544707208L, 0.0239544490709674941887988416318107990646L, 0.00299775294496053944060700963645084591246L, 0.00024478412843088575835960648397300177201L, 0.118424712755145205302405346348931402917e-4L, 0.2588206250858483868392167535345681119e-6L }; + static const float f0 = 0.549742341F; + r = tools::evaluate_rational(n, d, z - 3.75); + b = f0; + } + else if(z < 6.5) + { + // Worst case absolute error found: 3.352877573e-35 + static const T n[9] = { -0.00210683958249012010206456754123471415706L, 0.00146329021314062287670019911742786780092L, 0.00242029064025351202243048169807220157512L, 0.0011321990764681390160708960047630195582L, 0.000277123780759366982673218537550876769487L, 0.401236501288775561636453586216146028714e-4L, 0.347799938323835778216424009916867086167e-5L, 0.167678812729975154456097184107934455429e-6L, 0.346722083660429051057284107535869165775e-8L }; + static const T d[10] = { 1L, 1.22334833521124956366395053444841951468L, 0.661433457507589455018784737495591428263L, 0.206503622658778732280997770028712044451L, 0.0407323027711252752353388616742333806362L, 0.00519969889874877079704615143005539754407L, 0.000419679230772141031030427156828631265963L, 0.195896640254171597965013007459411704085e-4L, 0.405070207572551760879797790899826058473e-6L, -0.949400883467250846930389103621356900319e-17L }; + static const float f0 = 0.5556300282F; + r = tools::evaluate_polynomial(n, z - 5) / tools::evaluate_polynomial(d, z - 5); + b = f0; + } + else if(z < 8) + { + // Worst case absolute error found: 2.10254551e-36 + static const T n[9] = { -0.00107224589975857477185569028693588970638L, 0.00081159959093417892787006088639848404179L, 0.00105587689576932891666032146026668833287L, 0.000416243954540394829165805666548948771809L, 0.861189599093384016322579078144012057531e-4L, 0.105064862265647286966467927732505059558e-4L, 0.763674245263385902692134637353517251296e-6L, 0.306964079269190247526141442183490066292e-7L, 0.525762928524110511201313708396204710874e-9L }; + static const T d[9] = { 1L, 1.03391233015873996503551085347368889767L, 0.471295765635712684194436077437130977978L, 0.123736066749315618886080242926593910851L, 0.0204690897886919138685460664198600282119L, 0.00218521816743913946855947853274936296576L, 0.000147057386621380823003258590658747813774L, 0.570514093706434168568509838021466564264e-5L, 0.977166974697066620826028345712327325748e-7L }; + static const float f0 = 0.5588091016F; + r = tools::evaluate_rational(n, d, z - 6.5); + b = f0; + } + else if(z < 10) + { + // Worst case absolute error found: 8.006848023e-37 + static const T n[9] = { -0.000764310289345400483607004463638641680792L, 0.000375959928342415987920641866513058424701L, 0.000477297615927227258961911005347799033473L, 0.000165573027183931250708334564452626717999L, 0.296617493157889183515359094859055088531e-4L, 0.310848843632513098624143817615592253324e-5L, 0.192932185180269434271810693046412848027e-6L, 0.658630702075882625552897504189436319318e-8L, 0.952880249971934343233104137698620618851e-10L }; + static const T d[9] = { 1L, 0.885953297549629585611202995885653291163L, 0.345435500008639080844920938390800739845L, 0.0774289910213823638414558561872084410517L, 0.0109142290775434200609901181618181718948L, 0.000990815749814504617347317658063197107511L, 0.565801964505889288566864514277149126893e-4L, 0.185846832474795168475989869562411740416e-5L, 0.268875677412705938842038805073576012915e-7L }; + static const float f0 = 0.5606456399F; + r = tools::evaluate_rational(n, d, z - 8); + b = f0; + } + else if(z < 12.5) + { + // Worst case absolute error found: 1.920487881e-37 + static const T n[9] = { -0.00049563543942917072170112779531688430711L, 0.000181627479476470045833245371263435213396L, 0.000205326116055098869964168775605689851547L, 0.602131211119027087508128340443602490578e-4L, 0.904046610725767796892834734953040318357e-5L, 0.790026495730279360618915285828083295597e-6L, 0.407154634490633661408148126521656550974e-7L, 0.114947371191075676274146563385045083492e-8L, 0.136959786076422777905476122283384578138e-10L }; + static const T d[9] = { 1L, 0.738936412939629363226408445024616124644L, 0.239911614287295587917806937612822134282L, 0.0447038494121568822243673246874110377585L, 0.00522920850086320874490830611785659031521L, 0.000393238307986133717620560371515858231357L, 0.18566831172454022627187937328433090172e-4L, 0.503267648562793696253090536560738864711e-6L, 0.599643373938283798258195761814169705225e-8L }; + static const float f0 = 0.5619055629F; + r = tools::evaluate_rational(n, d, z - 10); + b = f0; + } + else if(z < 15.5) + { + // Worst case absolute error found: 1.257535398e-36 + static const T n[8] = { -0.000310716603972278501158850534578560332617L, 0.00011678083970731888844953949114132723885L, 0.800190190430061077253903477346761222901e-4L, 0.156297703728913451581100601056534652076e-4L, 0.151432948873760306237990776980248434808e-5L, 0.798843820137664551611401320879346402013e-7L, 0.219398460602279142004550137383605410162e-8L, 0.244774638611231694720102050826438123042e-10L }; + static const T d[9] = { 1L, 0.536396467095662522242258924420035847546L, 0.12368534422025248132153213926057643819L, 0.0158935327926481775020421628983323726346L, 0.00122923842249710594941031294559763761829L, 0.572250268558063378795115723535491980973e-4L, 0.148480028895780193980507551658637328542e-5L, 0.165653602646537759781637790321962585489e-7L, 0.159564067829807076335030582566349996674e-21L }; + static const float f0 = 0.5627119541F; + r = tools::evaluate_polynomial(n, z - 12.5) / tools::evaluate_polynomial(d, z - 12.5); + b = f0; + } + else if(z < 20) + { + // Worst case absolute error found: 8.757869781e-37 + static const T n[8] = { -0.000232165799411403604511899928682939571679L, 0.473280617901953093430938763139716601257e-4L, 0.322197983787538821545512424866901113822e-4L, 0.53341606003892328294004958671866936958e-5L, 0.429392533762301420884052643595872389588e-6L, 0.186707830002841677949013638707964861935e-7L, 0.420531779988891521855765212230340499168e-9L, 0.38311153882270641561622347190918577449e-11L }; + static const T d[9] = { 1L, 0.440698415779467873589164469370853517393L, 0.0834079018864546179293964148377602724235L, 0.00878845776227345123101968908701592510214L, 0.000556792236817609981676018545344816931862L, 0.212109697877283363015270621439889468055e-4L, 0.449886743173619367191275104721917344569e-6L, 0.409854405005280582884236774230760402868e-8L, 0.185071069100878210011727114952196630136e-23L }; + static const float f0 = 0.5632548332F; + r = tools::evaluate_polynomial(n, z - 15.5) / tools::evaluate_polynomial(d, z - 15.5); + b = f0; + } + else if(z < 26) + { + // Worst case absolute error found: 6.571456853e-37 + static const T n[8] = { -0.000143129243915019877016909310584833592972L, 0.203555078616578752774553439209122798188e-4L, 0.116664173863253360297276766667046754002e-4L, 0.153607643549360281089355497044679566329e-5L, 0.976486412462035616905934994399021437658e-7L, 0.33416295362298759817564985788402188186e-8L, 0.590812660432887787644458409396105030781e-10L, 0.421471133628743008309458424282421874073e-12L }; + static const T d[8] = { 1L, 0.346848503043261151874606241871432055165L, 0.0516236057301875770334953837585483539519L, 0.0042740199483843978391191804633398315544L, 0.000212586135154357046245694533825075007902L, 0.635258188334431428038271842518161892901e-5L, 0.105600415847309067601860633252823051505e-6L, 0.753327238218310630683194279382721367469e-9L }; + static const float f0 = 0.5636301041F; + r = tools::evaluate_polynomial(n, z - 20) / tools::evaluate_polynomial(d, z - 20); + b = f0; + } + else if(z < 34) + { + // Worst case absolute error found: 2.529847851e-38 + static const T n[8] = { -0.863162280463127451272161303767299107489e-4L, 0.876391266908317792353253474461536821127e-5L, 0.407624004719762912183133597708988715137e-5L, 0.418371930808379615690956857824418800194e-6L, 0.206376792034344913360458422974245946873e-7L, 0.546878311460852031076829190722479684e-9L, 0.74760305098509923829341087347518769626e-11L, 0.411832046806658129073165530819472782663e-13L }; + static const T d[9] = { 1L, 0.268714425336129161136892060316889824437L, 0.0309686025544536788982104017649851516554L, 0.00198426609900573235086828549632290797514L, 0.763402107420631006526499294753645914808e-4L, 0.176354119917411263184292422389304506735e-5L, 0.226504369338582253171306523992412653547e-7L, 0.124774448034213281307712525982862926228e-9L, 0.541581693417048102342931921476367282462e-28L }; + static const float f0 = 0.5638595223F; + r = tools::evaluate_polynomial(n, z - 26) / tools::evaluate_polynomial(d, z - 26); + b = f0; + } + else if(z < 46) + { + // Worst case absolute error found: 4.880939969e-36 + static const T n[7] = { -0.552701065525823960321509114250962372959e-4L, 0.459798238451342341380837226471283129117e-5L, 0.117462487430397988459985818542278619172e-5L, 0.704965053290383355071079647747711714696e-7L, 0.191250482739845326510859812663255140286e-8L, 0.245913419605775857221974833985059356312e-10L, 0.120466123381598216554945834019040289508e-12L }; + static const T d[8] = { 1L, 0.175852634004021068883919193145643406305L, 0.0128923775281953424344037205817061020944L, 0.000504385604406829419856756492198778141939L, 0.111061123996047697713589874603922096536e-4L, 0.130499191758882778721577274330215931713e-6L, 0.639279131688964342759306361922751772829e-9L, -0.10503012469906917938721140272475203112e-26L }; + static const float f0 = 0.564001143F; + r = tools::evaluate_polynomial(n, z - 34) / tools::evaluate_polynomial(d, z - 34); + b = f0; + } + else if(z < 62) + { + // Worst case absolute error found: 8.634961697e-37 + static const T n[7] = { -0.299551937061912926289705712581858190494e-4L, 0.188783643501597286680709990049243153264e-5L, 0.353403900815908094401075506391935032602e-6L, 0.156779149815977342177830075875441013335e-7L, 0.31456307256618424444443489905810774564e-9L, 0.29912544832845265905351204765862702307e-11L, 0.108360038290329929702659864116372774364e-13L }; + static const T d[7] = { 1L, 0.13020345740128026085404079010013007005L, 0.00706598549835633149505923515407700416484L, 0.000204578844720147762058725212299415091588L, 0.333280847765611305843836201217690887394e-5L, 0.289666303356425428524772241712503072453e-7L, 0.104933404691983708511908027657434756019e-9L }; + static const float f0 = 0.564086318F; + r = tools::evaluate_polynomial(n, z - 46) / tools::evaluate_polynomial(d, z - 46); + b = f0; + } + else if(z < 80) + { + // Worst case absolute error found: 6.10700166e-39 + static const T n[7] = { -0.146162619512779884168960178459825270831e-4L, 0.952303834226435420147786300516273108344e-6L, 0.114559890033396819882468040960469980168e-6L, 0.368994353517438072494331750992706039868e-8L, 0.545158660461829568567388818070830588533e-10L, 0.383569328729331398089160922704933035281e-12L, 0.103104113324271568678309317039606225294e-14L }; + static const T d[7] = { 1L, 0.0966822058944670599111360985490948186413L, 0.00389546596914826027568119425228340291579L, 0.837237328321088890541798035513749762375e-4L, 0.101236677684940943809478588316884539423e-5L, 0.652985528810044575089151077574382356898e-8L, 0.175523663960756825512727785416137345625e-10L }; + static const float f0 = 0.5641308427F; + r = tools::evaluate_polynomial(n, z - 62) / tools::evaluate_polynomial(d, z - 62); + b = f0; + } + else + { + // Worst case absolute error found: 3.409761622e-39 + static const T n[7] = { -0.103600733768855845278685109220598569282e-4L, 0.324846376725138276091774803419773168357e-6L, 0.376580042454826796817160322889753111347e-7L, 0.971125540805193703472871419997820785081e-9L, 0.112499588573918670534994853431614458564e-10L, 0.6161310085325929027114924903443564594e-13L, 0.128358125353302055468778305481781957985e-15L }; + static const T d[7] = { 1L, 0.0749579802028981336679035635535776767532L, 0.00234137768051079846068630120744888560113L, 0.390095348825177571970348898222511084593e-4L, 0.365628111271063883320224395719085602867e-6L, 0.182790705425846241876560215158605843026e-8L, 0.380806548535012144489621218246876843627e-11L }; + static const float f0 = 0.5641558766F; + r = tools::evaluate_polynomial(n, z - 80) / tools::evaluate_polynomial(d, z - 80); + b = f0; + } + T g = exp(-z * z) / z; + result = g * b + g * r; + } + else + { + // + // Any value of z larger than 110 will underflow to zero: + // + result = 0; + invert = !invert; + } + + if(invert) + { + result = 1 - result; + } + + return result; +} // template T erf_imp(T z, bool invert, const L& l, const mpl::int_<113>& t) + +} // namespace detail + +template +inline typename tools::promote_args::type erf(T z, const Policy& /* pol */) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::precision::type precision_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name()); + BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name()); + BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name()); + + typedef typename mpl::if_< + mpl::less_equal >, + mpl::int_<0>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<53>, // double + typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, // 80-bit long double + typename mpl::if_< + mpl::less_equal >, + mpl::int_<113>, // 128-bit long double + mpl::int_<0> // too many bits, use generic version. + >::type + >::type + >::type + >::type tag_type; + + BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name()); + + return policies::checked_narrowing_cast(detail::erf_imp( + static_cast(z), + false, + forwarding_policy(), + tag_type()), "boost::math::erf<%1%>(%1%, %1%)"); +} + +template +inline typename tools::promote_args::type erfc(T z, const Policy& /* pol */) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::precision::type precision_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name()); + BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name()); + BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name()); + + typedef typename mpl::if_< + mpl::less_equal >, + mpl::int_<0>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<53>, // double + typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, // 80-bit long double + typename mpl::if_< + mpl::less_equal >, + mpl::int_<113>, // 128-bit long double + mpl::int_<0> // too many bits, use generic version. + >::type + >::type + >::type + >::type tag_type; + + BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name()); + + return policies::checked_narrowing_cast(detail::erf_imp( + static_cast(z), + true, + forwarding_policy(), + tag_type()), "boost::math::erfc<%1%>(%1%, %1%)"); +} + +template +inline typename tools::promote_args::type erf(T z) +{ + return boost::math::erf(z, policies::policy<>()); +} + +template +inline typename tools::promote_args::type erfc(T z) +{ + return boost::math::erfc(z, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#include + +#endif // BOOST_MATH_SPECIAL_ERF_HPP + + + diff --git a/include/boost/math/special_functions/expm1.hpp b/include/boost/math/special_functions/expm1.hpp index a9fc3bbee..cb88a18d1 100644 --- a/include/boost/math/special_functions/expm1.hpp +++ b/include/boost/math/special_functions/expm1.hpp @@ -1,4 +1,4 @@ -// (C) Copyright John Maddock 2005. +// (C) Copyright John Maddock 2006. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,7 +9,13 @@ #include #include // platform's ::expm1 #include -#include +#include +#include +#include +#include +#include +#include +#include #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS # include @@ -17,87 +23,203 @@ # include #endif -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std{ using ::exp; using ::fabs; } -#endif - - namespace boost{ namespace math{ -namespace detail{ -// -// Functor expm1_series returns the next term in the Taylor series -// x^k / k! -// each time that operator() is invoked. -// -template -struct expm1_series +namespace detail { - typedef T result_type; + // Functor expm1_series returns the next term in the Taylor series + // x^k / k! + // each time that operator() is invoked. + // + template + struct expm1_series + { + typedef T result_type; - expm1_series(T x) - : k(0), m_x(x), m_term(1) {} + expm1_series(T x) + : k(0), m_x(x), m_term(1) {} - T operator()() - { - ++k; - m_term *= m_x; - m_term /= k; - return m_term; - } + T operator()() + { + ++k; + m_term *= m_x; + m_term /= k; + return m_term; + } - int count()const - { - return k; - } + int count()const + { + return k; + } -private: - int k; - const T m_x; - T m_term; - expm1_series(const expm1_series&); - expm1_series& operator=(const expm1_series&); -}; - -} // namespace + private: + int k; + const T m_x; + T m_term; + expm1_series(const expm1_series&); + expm1_series& operator=(const expm1_series&); + }; // // Algorithm expm1 is part of C99, but is not yet provided by many compilers. // // This version uses a Taylor series expansion for 0.5 > |x| > epsilon. // -template -T expm1(T x) +template +T expm1_imp(T x, const mpl::int_<0>&, const Policy& pol) { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(::std::numeric_limits::is_specialized); -#else - BOOST_ASSERT(std::numeric_limits::is_specialized); -#endif + BOOST_MATH_STD_USING - T a = std::fabs(x); + T a = fabs(x); if(a > T(0.5L)) - return std::exp(x) - T(1); - if(a < std::numeric_limits::epsilon()) + return exp(x) - T(1); + if(a < tools::epsilon()) return x; detail::expm1_series s(x); - T result = detail::kahan_sum_series(s, std::numeric_limits::digits + 2); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T result = tools::sum_series(s, policies::digits(), max_iter); +#else + T zero = 0; + T result = tools::sum_series(s, policies::digits(), max_iter, zero); +#endif + policies::check_series_iterations("boost::math::expm1<%1%>(%1%)", max_iter, pol); return result; } -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -inline float expm1(float z) + +template +T expm1_imp(T x, const mpl::int_<53>&, const P&) { - return expm1(z); + BOOST_MATH_STD_USING + + T a = fabs(x); + if(a > T(0.5L)) + return exp(x) - T(1); + if(a < tools::epsilon()) + return x; + + static const float Y = 0.10281276702880859e1f; + static const T n[] = { -0.28127670288085937e-1, 0.51278186299064534e0, -0.6310029069350198e-1, 0.11638457975729296e-1, -0.52143390687521003e-3, 0.21491399776965688e-4 }; + static const T d[] = { 1, -0.45442309511354755e0, 0.90850389570911714e-1, -0.10088963629815502e-1, 0.63003407478692265e-3, -0.17976570003654402e-4 }; + + T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x); + return result; } -inline double expm1(double z) + +template +T expm1_imp(T x, const mpl::int_<64>&, const P&) { - return expm1(z); + BOOST_MATH_STD_USING + + T a = fabs(x); + if(a > T(0.5L)) + return exp(x) - T(1); + if(a < tools::epsilon()) + return x; + + static const float Y = 0.10281276702880859375e1f; + static const T n[] = { + -0.281276702880859375e-1L, + 0.512980290285154286358e0L, + -0.667758794592881019644e-1L, + 0.131432469658444745835e-1L, + -0.72303795326880286965e-3L, + 0.447441185192951335042e-4L, + -0.714539134024984593011e-6L + }; + static const T d[] = { + 1, + -0.461477618025562520389e0L, + 0.961237488025708540713e-1L, + -0.116483957658204450739e-1L, + 0.873308008461557544458e-3L, + -0.387922804997682392562e-4L, + 0.807473180049193557294e-6L + }; + + T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x); + return result; } -inline long double expm1(long double z) + +template +T expm1_imp(T x, const mpl::int_<113>&, const P&) { - return expm1(z); + BOOST_MATH_STD_USING + + T a = fabs(x); + if(a > T(0.5L)) + return exp(x) - T(1); + if(a < tools::epsilon()) + return x; + + static const float Y = 0.10281276702880859375e1f; + static const T n[] = { + -0.28127670288085937499999999999999999854e-1L, + 0.51278156911210477556524452177540792214e0L, + -0.63263178520747096729500254678819588223e-1L, + 0.14703285606874250425508446801230572252e-1L, + -0.8675686051689527802425310407898459386e-3L, + 0.88126359618291165384647080266133492399e-4L, + -0.25963087867706310844432390015463138953e-5L, + 0.14226691087800461778631773363204081194e-6L, + -0.15995603306536496772374181066765665596e-8L, + 0.45261820069007790520447958280473183582e-10L + }; + static const T d[] = { + 1, + -0.45441264709074310514348137469214538853e0L, + 0.96827131936192217313133611655555298106e-1L, + -0.12745248725908178612540554584374876219e-1L, + 0.11473613871583259821612766907781095472e-2L, + -0.73704168477258911962046591907690764416e-4L, + 0.34087499397791555759285503797256103259e-5L, + -0.11114024704296196166272091230695179724e-6L, + 0.23987051614110848595909588343223896577e-8L, + -0.29477341859111589208776402638429026517e-10L, + 0.13222065991022301420255904060628100924e-12L + }; + + T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x); + return result; +} + +} // namespace detail + +template +inline typename tools::promote_args::type expm1(T x, const Policy& /* pol */) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::precision::type precision_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + typedef typename mpl::if_c< + ::std::numeric_limits::is_specialized == 0, + mpl::int_<0>, // no numeric_limits, use generic solution + typename mpl::if_< + typename mpl::less_equal >::type, + mpl::int_<53>, // double + typename mpl::if_< + typename mpl::less_equal >::type, + mpl::int_<64>, // 80-bit long double + typename mpl::if_< + typename mpl::less_equal >::type, + mpl::int_<113>, // 128-bit long double + mpl::int_<0> // too many bits, use generic version. + >::type + >::type + >::type + >::type tag_type; + + return policies::checked_narrowing_cast(detail::expm1_imp( + static_cast(x), + tag_type(), forwarding_policy()), "boost::math::expm1<%1%>(%1%)"); } -#endif #ifdef expm1 # ifndef BOOST_HAS_expm1 @@ -108,14 +230,40 @@ inline long double expm1(long double z) #ifdef BOOST_HAS_EXPM1 # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) -inline float expm1(float x){ return ::expm1f(x); } -inline long double expm1(long double x){ return ::expm1l(x); } +inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); } +inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); } #else -inline float expm1(float x){ return ::expm1(x); } +inline float expm1(float x, const policies::policy<>&){ return ::expm1(x); } #endif -inline double expm1(double x){ return ::expm1(x); } +inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); } #endif -} } // namespaces +template +inline typename tools::promote_args::type expm1(T x) +{ + return expm1(x, policies::policy<>()); +} + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +inline float expm1(float z) +{ + return expm1(z); +} +inline double expm1(double z) +{ + return expm1(z); +} +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +inline long double expm1(long double z) +{ + return expm1(z); +} +#endif +#endif + +} // namespace math +} // namespace boost #endif // BOOST_MATH_HYPOT_INCLUDED + + diff --git a/include/boost/math/special_functions/factorials.hpp b/include/boost/math/special_functions/factorials.hpp new file mode 100644 index 000000000..8bb640d1d --- /dev/null +++ b/include/boost/math/special_functions/factorials.hpp @@ -0,0 +1,224 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SP_FACTORIALS_HPP +#define BOOST_MATH_SP_FACTORIALS_HPP + +#include +#include +#include +#include +#ifdef BOOST_MSVC +#pragma warning(push) // Temporary until lexical cast fixed. +#pragma warning(disable: 4127 4701) +#endif +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +#include + +namespace boost { namespace math +{ + +template +inline T factorial(unsigned i, const Policy& pol) +{ + BOOST_MATH_STD_USING // Aid ADL for floor. + + if(i <= max_factorial::value) + return unchecked_factorial(i); + T result = boost::math::tgamma(static_cast(i+1), pol); + if(result > tools::max_value()) + return result; // Overflowed value! (But tgamma will have signalled the error already). + return floor(result + 0.5f); +} + +template +inline T factorial(unsigned i) +{ + return factorial(i, policies::policy<>()); +} +/* +// Can't have these in a policy enabled world? +template<> +inline float factorial(unsigned i) +{ + if(i <= max_factorial::value) + return unchecked_factorial(i); + return tools::overflow_error(BOOST_CURRENT_FUNCTION); +} + +template<> +inline double factorial(unsigned i) +{ + if(i <= max_factorial::value) + return unchecked_factorial(i); + return tools::overflow_error(BOOST_CURRENT_FUNCTION); +} +*/ +template +T double_factorial(unsigned i, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL lookup of std names + if(i & 1) + { + // odd i: + if(i < max_factorial::value) + { + unsigned n = (i - 1) / 2; + return ceil(unchecked_factorial(i) / (ldexp(T(1), (int)n) * unchecked_factorial(n)) - 0.5f); + } + // + // Fallthrough: i is too large to use table lookup, try the + // gamma function instead. + // + T result = boost::math::tgamma(static_cast(i) / 2 + 1, pol) / sqrt(constants::pi()); + if(ldexp(tools::max_value(), -static_cast(i+1) / 2) > result) + return ceil(result * ldexp(T(1), (i+1) / 2) - 0.5f); + } + else + { + // even i: + unsigned n = i / 2; + T result = factorial(n, pol); + if(ldexp(tools::max_value(), -(int)n) > result) + return result * ldexp(T(1), (int)n); + } + // + // If we fall through to here then the result is infinite: + // + return policies::raise_overflow_error("boost::math::double_factorial<%1%>(unsigned)", 0, pol); +} + +template +inline T double_factorial(unsigned i) +{ + return double_factorial(i, policies::policy<>()); +} + +namespace detail{ + +template +T rising_factorial_imp(T x, int n, const Policy& pol) +{ + if(x < 0) + { + // + // For x less than zero, we really have a falling + // factorial, modulo a possible change of sign. + // + // Note that the falling factorial isn't defined + // for negative n, so we'll get rid of that case + // first: + // + bool inv = false; + if(n < 0) + { + x += n; + n = -n; + inv = true; + } + T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol); + if(inv) + result = 1 / result; + return result; + } + if(n == 0) + return 1; + // + // We don't optimise this for small n, because + // tgamma_delta_ratio is alreay optimised for that + // use case: + // + return 1 / boost::math::tgamma_delta_ratio(x, static_cast(n), pol); +} + +template +inline T falling_factorial_imp(T x, unsigned n, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std names + if(x == 0) + return 0; + if(x < 0) + { + // + // For x < 0 we really have a rising factorial + // modulo a possible change of sign: + // + return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol); + } + if(n == 0) + return 1; + if(x < n-1) + { + // + // x+1-n will be negative and tgamma_delta_ratio won't + // handle it, split the product up into three parts: + // + T xp1 = x + 1; + unsigned n2 = tools::real_cast(floor(xp1)); + if(n2 == xp1) + return 0; + T result = boost::math::tgamma_delta_ratio(xp1, -static_cast(n2), pol); + x -= n2; + result *= x; + ++n2; + if(n2 < n) + result *= falling_factorial(x - 1, n - n2, pol); + return result; + } + // + // Simple case: just the ratio of two + // (positive argument) gamma functions. + // Note that we don't optimise this for small n, + // because tgamma_delta_ratio is alreay optimised + // for that use case: + // + return boost::math::tgamma_delta_ratio(x + 1, -static_cast(n), pol); +} + +} // namespace detail + +template +inline typename tools::promote_args::type + falling_factorial(RT x, unsigned n) +{ + typedef typename tools::promote_args::type result_type; + return detail::falling_factorial_imp( + static_cast(x), n, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + falling_factorial(RT x, unsigned n, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::falling_factorial_imp( + static_cast(x), n, pol); +} + +template +inline typename tools::promote_args::type + rising_factorial(RT x, int n) +{ + typedef typename tools::promote_args::type result_type; + return detail::rising_factorial_imp( + static_cast(x), n, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + rising_factorial(RT x, int n, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::rising_factorial_imp( + static_cast(x), n, pol); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SP_FACTORIALS_HPP diff --git a/include/boost/math/special_functions/fpclassify.hpp b/include/boost/math/special_functions/fpclassify.hpp new file mode 100644 index 000000000..f777bdba5 --- /dev/null +++ b/include/boost/math/special_functions/fpclassify.hpp @@ -0,0 +1,240 @@ +// Copyright John Maddock 2005-2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_FPCLASSIFY_HPP +#define BOOST_MATH_FPCLASSIFY_HPP + +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#include +#endif + +#ifdef BOOST_NO_STDC_NAMESPACE + namespace std{ using ::abs; using ::fabs; } +#endif + +#ifndef FP_NORMAL + +#define FP_ZERO 0 +#define FP_NORMAL 1 +#define FP_INFINITE 2 +#define FP_NAN 3 +#define FP_SUBNORMAL 4 + +#else + +#define BOOST_HAS_FPCLASSIFY + +#ifndef fpclassify +# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) && defined(_GLIBCXX_USE_C99_MATH) && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0)) +# define BOOST_FPCLASSIFY_PREFIX ::std:: +# else +# undef BOOST_HAS_FPCLASSIFY +# define BOOST_FPCLASSIFY_PREFIX +# endif +#elif (defined(__HP_aCC) && !defined(__hppa)) +// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit! +# define BOOST_FPCLASSIFY_PREFIX :: +#else +# define BOOST_FPCLASSIFY_PREFIX +#endif + +#ifdef __MINGW32__ +# undef BOOST_HAS_FPCLASSIFY +#endif + +#endif + +namespace boost{ + +#if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan) +// +// This must not be located in any namespace under boost::math +// otherwise we can get into an infinite loop if isnan is +// a #define for "isnan" ! +// +namespace math_detail{ + +template +inline bool is_nan_helper(T t, const boost::true_type&) +{ +#ifdef isnan + return isnan(t); +#else // BOOST_HAS_FPCLASSIFY + return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == FP_NAN); +#endif +} + +template +inline bool is_nan_helper(T t, const boost::false_type&) +{ + return false; +} + +} + +#endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan) + +namespace math{ + +namespace detail{ + +template +inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::true_&) +{ + // whenever possible check for Nan's first: +#ifdef BOOST_HAS_FPCLASSIFY + if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point())) + return FP_NAN; +#elif defined(isnan) + if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point())) + return FP_NAN; +#elif defined(_MSC_VER) || defined(__BORLANDC__) + if(::_isnan(boost::math::tools::real_cast(t))) + return FP_NAN; +#endif + // std::fabs broken on a few systems especially for long long!!!! + T at = (t < T(0)) ? -t : t; + + // Use a process of exclusion to figure out + // what kind of type we have, this relies on + // IEEE conforming reals that will treat + // Nan's as unordered. Some compilers + // don't do this once optimisations are + // turned on, hence the check for nan's above. + if(at <= (std::numeric_limits::max)()) + { + if(at >= (std::numeric_limits::min)()) + return FP_NORMAL; + return (at != 0) ? FP_SUBNORMAL : FP_ZERO; + } + else if(at > (std::numeric_limits::max)()) + return FP_INFINITE; + return FP_NAN; +} + +template +inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::false_&) +{ + // + // An unknown type with no numeric_limits support, + // so what are we supposed to do we do here? + // + return t == 0 ? FP_ZERO : FP_NORMAL; +} + +} // namespace detail + +template +inline int fpclassify BOOST_NO_MACRO_EXPAND(T t) +{ +#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + if(std::numeric_limits::is_specialized) + return detail::fpclassify_imp(t, mpl::true_()); + return detail::fpclassify_imp(t, mpl::false_()); +#else + return detail::fpclassify_imp(t, mpl::bool_< ::std::numeric_limits::is_specialized>()); +#endif +} + +#if defined(BOOST_HAS_FPCLASSIFY) +inline int fpclassify BOOST_NO_MACRO_EXPAND(float t) +{ + return BOOST_FPCLASSIFY_PREFIX fpclassify(t); +} +inline int fpclassify BOOST_NO_MACRO_EXPAND(double t) +{ + return BOOST_FPCLASSIFY_PREFIX fpclassify(t); +} +#if !defined(__CYGWIN__) && !defined(__HP_aCC) && !defined(BOOST_INTEL) && !defined(BOOST_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) +// The native fpclassify broken for long doubles with aCC +// use portable one instead.... +inline int fpclassify BOOST_NO_MACRO_EXPAND(long double t) +{ + return BOOST_FPCLASSIFY_PREFIX fpclassify(t); +} +#endif + +#elif defined(_MSC_VER) +// This only works for type double, for both float +// and long double it gives misleading answers. +inline int fpclassify BOOST_NO_MACRO_EXPAND(double t) +{ + switch(::_fpclass(t)) + { + case _FPCLASS_SNAN /* Signaling NaN */ : + case _FPCLASS_QNAN /* Quiet NaN */ : + return FP_NAN; + case _FPCLASS_NINF /*Negative infinity ( –INF) */ : + case _FPCLASS_PINF /* Positive infinity (+INF) */ : + return FP_INFINITE; + case _FPCLASS_NN /* Negative normalized non-zero */ : + case _FPCLASS_PN /* Positive normalized non-zero */ : + return FP_NORMAL; + case _FPCLASS_ND /* Negative denormalized */: + case _FPCLASS_PD /* Positive denormalized */ : + return FP_SUBNORMAL; + case _FPCLASS_NZ /* Negative zero ( – 0) */ : + case _FPCLASS_PZ /* Positive 0 (+0) */ : + return FP_ZERO; + default: + /**/ ; + } + return FP_NAN; // should never get here!!! +} +#endif + +template +inline bool isfinite BOOST_NO_MACRO_EXPAND(T z) +{ + int t = (::boost::math::fpclassify)(z); + return (t != FP_NAN) && (t != FP_INFINITE); +} + +template +inline bool isinf BOOST_NO_MACRO_EXPAND(T t) +{ + return (::boost::math::fpclassify)(t) == FP_INFINITE; +} + +template +inline bool isnan BOOST_NO_MACRO_EXPAND(T t) +{ + return (::boost::math::fpclassify)(t) == FP_NAN; +} +#ifdef isnan +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); } +#elif defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' +# pragma warning(disable: 4244) // conversion from 'long double' to 'double', +// No possible loss of data because they are same size. +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(float t){ return _isnan(t); } +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(double t){ return _isnan(t); } +template <> inline bool isnan BOOST_NO_MACRO_EXPAND(long double t){ return _isnan(t); } +#pragma warning (pop) +#endif + +template +inline bool isnormal BOOST_NO_MACRO_EXPAND(T t) +{ + return (::boost::math::fpclassify)(t) == FP_NORMAL; +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_FPCLASSIFY_HPP + + + diff --git a/include/boost/math/special_functions/gamma.hpp b/include/boost/math/special_functions/gamma.hpp new file mode 100644 index 000000000..11706ad38 --- /dev/null +++ b/include/boost/math/special_functions/gamma.hpp @@ -0,0 +1,1471 @@ +// Copyright John Maddock 2006-7. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_GAMMA_HPP +#define BOOST_MATH_SF_GAMMA_HPP + +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127 4701) +// // For lexical_cast, until fixed in 1.35? +// // conditional expression is constant & +// // Potentially uninitialized local variable 'name' used +#endif +#include +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_MATH_INSTRUMENT +#include +#include +#include +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code (return after domain_error throw). +# pragma warning(disable: 4127) // conditional expression is constant. +# pragma warning(disable: 4100) // unreferenced formal parameter. +// Several variables made comments, +// but some difficulty as whether referenced on not may depend on macro values. +// So to be safe, 4100 warnings suppressed. +// TODO - revisit this? +#endif + +namespace boost{ namespace math{ + +namespace detail{ + +template +inline bool is_odd(T v, const boost::true_type&) +{ + int i = static_cast(v); + return i&1; +} +template +inline bool is_odd(T v, const boost::false_type&) +{ + // Oh dear can't cast T to int! + BOOST_MATH_STD_USING + T modulus = v - 2 * floor(v/2); + return static_cast(modulus != 0); +} +template +inline bool is_odd(T v) +{ + return is_odd(v, ::boost::is_convertible()); +} + +template +T sinpx(T z) +{ + // Ad hoc function calculates x * sin(pi * x), + // taking extra care near when x is near a whole number. + BOOST_MATH_STD_USING + int sign = 1; + if(z < 0) + { + z = -z; + } + else + { + sign = -sign; + } + T fl = floor(z); + T dist; + if(is_odd(fl)) + { + fl += 1; + dist = fl - z; + sign = -sign; + } + else + { + dist = z - fl; + } + BOOST_ASSERT(fl >= 0); + if(dist > 0.5) + dist = 1 - dist; + T result = sin(dist*boost::math::constants::pi()); + return sign*z*result; +} // template T sinpx(T z) +// +// tgamma(z), with Lanczos support: +// +template +T gamma_imp(T z, const Policy& pol, const L& l) +{ + BOOST_MATH_STD_USING + + T result = 1; + +#ifdef BOOST_MATH_INSTRUMENT + static bool b = false; + if(!b) + { + std::cout << "tgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl; + b = true; + } +#endif + static const char* function = "boost::math::tgamma<%1%>(%1%)"; + + if((z <= 0) && (floor(z) == z)) + return policies::raise_pole_error(function, "Evaluation of tgamma at a negative integer %1%.", z, pol); + if(z <= -20) + { + result = gamma_imp(-z, pol, l) * sinpx(z); + if((fabs(result) < 1) && (tools::max_value() * fabs(result) < boost::math::constants::pi())) + return policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + result = -boost::math::constants::pi() / result; + if(result == 0) + return policies::raise_underflow_error(function, "Result of tgamma is too small to represent.", pol); + if((boost::math::fpclassify)(result) == FP_SUBNORMAL) + return policies::raise_denorm_error(function, "Result of tgamma is denormalized.", result, pol); + return result; + } + + // shift z to > 1: + while(z < 1) + { + result /= z; + z += 1; + } + if((floor(z) == z) && (z < max_factorial::value)) + { + result *= unchecked_factorial(tools::real_cast(z) - 1); + } + else + { + result *= L::lanczos_sum(z); + if(z * log(z) > tools::log_max_value()) + { + // we're going to overflow unless this is done with care: + T zgh = (z + static_cast(L::g()) - boost::math::constants::half()); + if(log(zgh) * z / 2 > tools::log_max_value()) + return policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + T hp = pow(zgh, (z / 2) - T(0.25)); + result *= hp / exp(zgh); + if(tools::max_value() / hp < result) + return policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + result *= hp; + } + else + { + T zgh = (z + static_cast(L::g()) - boost::math::constants::half()); + result *= pow(zgh, z - boost::math::constants::half()) / exp(zgh); + } + } + return result; +} +// +// lgamma(z) with Lanczos support: +// +template +T lgamma_imp(T z, const Policy& pol, const L& l, int* sign = 0) +{ +#ifdef BOOST_MATH_INSTRUMENT + static bool b = false; + if(!b) + { + std::cout << "lgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl; + b = true; + } +#endif + + BOOST_MATH_STD_USING + + static const char* function = "boost::math::lgamma<%1%>(%1%)"; + + T result = 0; + int sresult = 1; + if(z <= 0) + { + // reflection formula: + if(floor(z) == z) + return policies::raise_pole_error(function, "Evaluation of lgamma at a negative integer %1%.", z, pol); + + T t = sinpx(z); + z = -z; + if(t < 0) + { + t = -t; + } + else + { + sresult = -sresult; + } + result = log(boost::math::constants::pi()) - lgamma_imp(z, pol, l) - log(t); + } + else if(z < 15) + { + typedef typename policies::precision::type precision_type; + typedef typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<113>, mpl::int_<0> >::type + >::type tag_type; + result = lgamma_small_imp(z, z - 1, z - 2, tag_type(), pol, l); + } + else if((z >= 3) && (z < 100)) + { + // taking the log of tgamma reduces the error, no danger of overflow here: + result = log(gamma_imp(z, pol, l)); + } + else + { + // regular evaluation: + T zgh = static_cast(z + L::g() - boost::math::constants::half()); + T l = L::lanczos_sum_expG_scaled(z); + result = log(zgh) - 1; + result *= z - 0.5f; + result += log(l); + } + + if(sign) + *sign = sresult; + return result; +} + +// +// Incomplete gamma functions follow: +// +template +struct upper_incomplete_gamma_fract +{ +private: + T z, a; + int k; +public: + typedef std::pair result_type; + + upper_incomplete_gamma_fract(T a1, T z1) + : z(z1-a1+1), a(a1), k(0) + { + } + + result_type operator()() + { + ++k; + z += 2; + return result_type(k * (a - k), z); + } +}; + +template +inline T upper_gamma_fraction(T a, T z, int bits) +{ + // Multiply result by z^a * e^-z to get the full + // upper incomplete integral. Divide by tgamma(z) + // to normalise. + upper_incomplete_gamma_fract f(a, z); + return 1 / (z - a + 1 + boost::math::tools::continued_fraction_a(f, bits)); +} + +template +struct lower_incomplete_gamma_series +{ +private: + T a, z, result; +public: + typedef T result_type; + lower_incomplete_gamma_series(T a1, T z1) : a(a1), z(z1), result(1){} + + T operator()() + { + T r = result; + a += 1; + result *= z/a; + return r; + } +}; + +template +inline T lower_gamma_series(T a, T z, const Policy& pol) +{ + // Multiply result by ((z^a) * (e^-z) / a) to get the full + // lower incomplete integral. Then divide by tgamma(a) + // to get the normalised value. + lower_incomplete_gamma_series s(a, z); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + int bits = policies::digits(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T zero = 0; + T result = boost::math::tools::sum_series(s, bits, max_iter, zero); +#else + T result = boost::math::tools::sum_series(s, bits, max_iter); +#endif + policies::check_series_iterations("boost::math::detail::lower_gamma_series<%1%>(%1%)", max_iter, pol); + return result; +} + +// +// Fully generic tgamma and lgamma use the incomplete partial +// sums added together: +// +template +T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l) +{ + static const char* function = "boost::math::tgamma<%1%>(%1%)"; + BOOST_MATH_STD_USING + if((z <= 0) && (floor(z) == z)) + return policies::raise_pole_error(function, "Evaluation of tgamma at a negative integer %1%.", z, pol); + if(z <= -20) + { + T result = gamma_imp(-z, pol, l) * sinpx(z); + if((fabs(result) < 1) && (tools::max_value() * fabs(result) < boost::math::constants::pi())) + return policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + result = -boost::math::constants::pi() / result; + if(result == 0) + return policies::raise_underflow_error(function, "Result of tgamma is too small to represent.", pol); + if((boost::math::fpclassify)(result) == FP_SUBNORMAL) + return policies::raise_denorm_error(function, "Result of tgamma is denormalized.", result, pol); + return result; + } + // + // The upper gamma fraction is *very* slow for z < 6, actually it's very + // slow to converge everywhere but recursing until z > 6 gets rid of the + // worst of it's behaviour. + // + T prefix = 1; + while(z < 6) + { + prefix /= z; + z += 1; + } + BOOST_MATH_INSTRUMENT_CODE(prefix); + if((floor(z) == z) && (z < max_factorial::value)) + { + prefix *= unchecked_factorial(tools::real_cast(z) - 1); + } + else + { + prefix = prefix * pow(z / boost::math::constants::e(), z); + BOOST_MATH_INSTRUMENT_CODE(prefix); + T sum = detail::lower_gamma_series(z, z, pol) / z; + BOOST_MATH_INSTRUMENT_CODE(sum); + sum += detail::upper_gamma_fraction(z, z, ::boost::math::policies::digits()); + BOOST_MATH_INSTRUMENT_CODE(sum); + if(fabs(tools::max_value() / prefix) < fabs(sum)) + return policies::raise_overflow_error(function, "Result of tgamma is too large to represent.", pol); + BOOST_MATH_INSTRUMENT_CODE((sum * prefix)); + return sum * prefix; + } + return prefix; +} + +template +T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l, int*sign) +{ + BOOST_MATH_STD_USING + + static const char* function = "boost::math::lgamma<%1%>(%1%)"; + T result = 0; + int sresult = 1; + if(z <= 0) + { + if(floor(z) == z) + return policies::raise_pole_error(function, "Evaluation of tgamma at a negative integer %1%.", z, pol); + T t = detail::sinpx(z); + z = -z; + if(t < 0) + { + t = -t; + } + else + { + sresult = -sresult; + } + result = log(boost::math::constants::pi()) - lgamma_imp(z, pol, l, 0) - log(t); + } + else if((z != 1) && (z != 2)) + { + T limit = (std::max)(z+1, T(10)); + T prefix = z * log(limit) - limit; + T sum = detail::lower_gamma_series(z, limit, pol) / z; + sum += detail::upper_gamma_fraction(z, limit, ::boost::math::policies::digits()); + result = log(sum) + prefix; + } + if(sign) + *sign = sresult; + return result; +} +// +// This helper calculates tgamma(dz+1)-1 without cancellation errors, +// used by the upper incomplete gamma with z < 1: +// +template +T tgammap1m1_imp(T dz, Policy const& pol, const L& l) +{ + BOOST_MATH_STD_USING + + typedef typename policies::precision::type precision_type; + + typedef typename mpl::if_< + mpl::or_< + mpl::less_equal >, + mpl::greater > + >, + typename mpl::if_< + is_same, + mpl::int_<113>, + mpl::int_<0> + >::type, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, mpl::int_<113> >::type + >::type tag_type; + + T result; + if(dz < 0) + { + if(dz < -0.5) + { + // Best method is simply to subtract 1 from tgamma: + result = boost::math::tgamma(1+dz, pol) - 1; + BOOST_MATH_INSTRUMENT_CODE(result); + } + else + { + // Use expm1 on lgamma: + result = boost::math::expm1(-boost::math::log1p(dz, pol) + + lgamma_small_imp(dz+2, dz + 1, dz, tag_type(), pol, l)); + BOOST_MATH_INSTRUMENT_CODE(result); + } + } + else + { + if(dz < 2) + { + // Use expm1 on lgamma: + result = boost::math::expm1(lgamma_small_imp(dz+1, dz, dz-1, tag_type(), pol, l), pol); + BOOST_MATH_INSTRUMENT_CODE(result); + } + else + { + // Best method is simply to subtract 1 from tgamma: + result = boost::math::tgamma(1+dz, pol) - 1; + BOOST_MATH_INSTRUMENT_CODE(result); + } + } + + return result; +} + +template +inline T tgammap1m1_imp(T dz, Policy const& pol, + const ::boost::math::lanczos::undefined_lanczos& l) +{ + BOOST_MATH_STD_USING // ADL of std names + // + // There should be a better solution than this, but the + // algebra isn't easy for the general case.... + // Start by subracting 1 from tgamma: + // + T result = gamma_imp(1 + dz, pol, l) - 1; + BOOST_MATH_INSTRUMENT_CODE(result); + // + // Test the level of cancellation error observed: we loose one bit + // for each power of 2 the result is less than 1. If we would get + // more bits from our most precise lgamma rational approximation, + // then use that instead: + // + BOOST_MATH_INSTRUMENT_CODE((dz > -0.5)); + BOOST_MATH_INSTRUMENT_CODE((dz < 2)); + BOOST_MATH_INSTRUMENT_CODE((ldexp(1.0, boost::math::policies::digits()) * fabs(result) < 1e34)); + if((dz > -0.5) && (dz < 2) && (ldexp(1.0, boost::math::policies::digits()) * fabs(result) < 1e34)) + { + result = tgammap1m1_imp(dz, pol, boost::math::lanczos::lanczos24m113()); + BOOST_MATH_INSTRUMENT_CODE(result); + } + return result; +} + +// +// Series representation for upper fraction when z is small: +// +template +struct small_gamma2_series +{ + typedef T result_type; + + small_gamma2_series(T a_, T x_) : result(-x_), x(-x_), apn(a_+1), n(1){} + + T operator()() + { + T r = result / (apn); + result *= x; + result /= ++n; + apn += 1; + return r; + } + +private: + T result, x, apn; + int n; +}; +// +// calculate power term prefix (z^a)(e^-z) used in the non-normalised +// incomplete gammas: +// +template +T full_igamma_prefix(T a, T z, const Policy& pol) +{ + BOOST_MATH_STD_USING + + T prefix; + T alz = a * log(z); + + if(z >= 1) + { + if((alz < tools::log_max_value()) && (-z > tools::log_min_value())) + { + prefix = pow(z, a) * exp(-z); + } + else if(a >= 1) + { + prefix = pow(z / exp(z/a), a); + } + else + { + prefix = exp(alz - z); + } + } + else + { + if(alz > tools::log_min_value()) + { + prefix = pow(z, a) * exp(-z); + } + else if(z/a < tools::log_max_value()) + { + prefix = pow(z / exp(z/a), a); + } + else + { + prefix = exp(alz - z); + } + } + // + // This error handling isn't very good: it happens after the fact + // rather than before it... + // + if((boost::math::fpclassify)(prefix) == FP_INFINITE) + policies::raise_overflow_error("boost::math::detail::full_igamma_prefix<%1%>(%1%, %1%)", "Result of incomplete gamma function is too large to represent.", pol); + + return prefix; +} +// +// Compute (z^a)(e^-z)/tgamma(a) +// most if the error occurs in this function: +// +template +T regularised_gamma_prefix(T a, T z, const Policy& pol, const L& l) +{ + BOOST_MATH_STD_USING + T agh = a + static_cast(L::g()) - T(0.5); + T prefix; + T d = ((z - a) - static_cast(L::g()) + T(0.5)) / agh; + + if(a < 1) + { + // + // We have to treat a < 1 as a special case because our Lanczos + // approximations are optimised against the factorials with a > 1, + // and for high precision types especially (128-bit reals for example) + // very small values of a can give rather eroneous results for gamma + // unless we do this: + // + // TODO: is this still required? Lanczos approx should be better now? + // + if(z <= tools::log_min_value()) + { + // Oh dear, have to use logs, should be free of cancellation errors though: + return exp(a * log(z) - z - lgamma_imp(a, pol, l)); + } + else + { + // direct calculation, no danger of overflow as gamma(a) < 1/a + // for small a. + return pow(z, a) * exp(-z) / gamma_imp(a, pol, l); + } + } + else if((fabs(d*d*a) <= 100) && (a > 150)) + { + // special case for large a and a ~ z. + prefix = a * boost::math::log1pmx(d, pol) + z * static_cast(0.5 - L::g()) / agh; + prefix = exp(prefix); + } + else + { + // + // general case. + // direct computation is most accurate, but use various fallbacks + // for different parts of the problem domain: + // + T alz = a * log(z / agh); + T amz = a - z; + if(((std::min)(alz, amz) <= tools::log_min_value()) || ((std::max)(alz, amz) >= tools::log_max_value())) + { + T amza = amz / a; + if(((std::min)(alz, amz)/2 > tools::log_min_value()) && ((std::max)(alz, amz)/2 < tools::log_max_value())) + { + // compute square root of the result and then square it: + T sq = pow(z / agh, a / 2) * exp(amz / 2); + prefix = sq * sq; + } + else if(((std::min)(alz, amz)/4 > tools::log_min_value()) && ((std::max)(alz, amz)/4 < tools::log_max_value()) && (z > a)) + { + // compute the 4th root of the result then square it twice: + T sq = pow(z / agh, a / 4) * exp(amz / 4); + prefix = sq * sq; + prefix *= prefix; + } + else if((amza > tools::log_min_value()) && (amza < tools::log_max_value())) + { + prefix = pow((z * exp(amza)) / agh, a); + } + else + { + prefix = exp(alz + amz); + } + } + else + { + prefix = pow(z / agh, a) * exp(amz); + } + } + prefix *= sqrt(agh / boost::math::constants::e()) / L::lanczos_sum_expG_scaled(a); + return prefix; +} +// +// And again, without Lanczos support: +// +template +T regularised_gamma_prefix(T a, T z, const Policy& pol, const lanczos::undefined_lanczos&) +{ + BOOST_MATH_STD_USING + + T limit = (std::max)(T(10), a); + T sum = detail::lower_gamma_series(a, limit, pol) / a; + sum += detail::upper_gamma_fraction(a, limit, ::boost::math::policies::digits()); + + if(a < 10) + { + // special case for small a: + T prefix = pow(z / 10, a); + prefix *= exp(10-z); + if(0 == prefix) + { + prefix = pow((z * exp((10-z)/a)) / 10, a); + } + prefix /= sum; + return prefix; + } + + T zoa = z / a; + T amz = a - z; + T alzoa = a * log(zoa); + T prefix; + if(((std::min)(alzoa, amz) <= tools::log_min_value()) || ((std::max)(alzoa, amz) >= tools::log_max_value())) + { + T amza = amz / a; + if((amza <= tools::log_min_value()) || (amza >= tools::log_max_value())) + { + prefix = exp(alzoa + amz); + } + else + { + prefix = pow(zoa * exp(amza), a); + } + } + else + { + prefix = pow(zoa, a) * exp(amz); + } + prefix /= sum; + return prefix; +} +// +// Upper gamma fraction for very small a: +// +template +inline T tgamma_small_upper_part(T a, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std functions. + // + // Compute the full upper fraction (Q) when a is very small: + // + T result; + result = boost::math::tgamma1pm1(a, pol) - boost::math::powm1(x, a, pol); + result /= a; + detail::small_gamma2_series s(a, x); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T zero = 0; + result -= pow(x, a) * tools::sum_series(s, boost::math::policies::digits(), max_iter, zero); +#else + result -= pow(x, a) * tools::sum_series(s, boost::math::policies::digits(), max_iter); +#endif + policies::check_series_iterations("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol); + return result; +} +// +// Upper gamma fraction for integer a: +// +template +inline T finite_gamma_q(T a, T x) +{ + // + // Calculates normalised Q when a is an integer: + // + BOOST_MATH_STD_USING + T sum = exp(-x); + if(sum != 0) + { + T term = sum; + for(unsigned n = 1; n < a; ++n) + { + term /= n; + term *= x; + sum += term; + } + } + return sum; +} +// +// Upper gamma fraction for half integer a: +// +template +T finite_half_gamma_q(T a, T x, T* p_derivative, const Policy& pol) +{ + // + // Calculates normalised Q when a is a half-integer: + // + BOOST_MATH_STD_USING + T e = boost::math::erfc(sqrt(x), pol); + if((e != 0) && (a > 1)) + { + T term = exp(-x) / sqrt(constants::pi() * x); + term *= x; + static const T half = T(1) / 2; + term /= half; + T sum = term; + for(unsigned n = 2; n < a; ++n) + { + term /= n - half; + term *= x; + sum += term; + } + e += sum; + if(p_derivative) + { + *p_derivative = 0; + } + } + else if(p_derivative) + { + // We'll be dividing by x later, so calculate derivative * x: + *p_derivative = sqrt(x) * exp(-x) / constants::root_pi(); + } + return e; +} +// +// Main incomplete gamma entry point, handles all four incomplete gamma's: +// +template +T gamma_incomplete_imp(T a, T x, bool normalised, bool invert, + const Policy& pol, T* p_derivative) +{ + static const char* function = "boost::math::gamma_p<%1%>(%1%, %1%)"; + if(a <= 0) + policies::raise_domain_error(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol); + if(x < 0) + policies::raise_domain_error(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol); + + BOOST_MATH_STD_USING + + typedef typename lanczos::lanczos::type lanczos_type; + + T result; + + BOOST_ASSERT((p_derivative == 0) || (normalised == true)); + + bool is_int = floor(a) == a; + bool is_half_int = (floor(2 * a) == 2 * a) && !is_int; + bool is_small_a = (a < 30) && (a <= x + 1); + + if(is_int && is_small_a && (x > 0.6)) + { + // calculate Q via finite sum: + invert = !invert; + result = finite_gamma_q(a, x); + if(normalised == false) + result *= boost::math::tgamma(a, pol); + // TODO: calculate derivative inside sum: + if(p_derivative) + *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type()); + } + else if(is_half_int && is_small_a && (x > 0.2)) + { + // calculate Q via finite sum for half integer a: + invert = !invert; + result = finite_half_gamma_q(a, x, p_derivative, pol); + if(normalised == false) + result *= boost::math::tgamma(a, pol); + if(p_derivative && (*p_derivative == 0)) + *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type()); + } + else if(x < 0.5) + { + // + // Changeover criterion chosen to give a changeover at Q ~ 0.33 + // + if(-0.4 / log(x) < a) + { + // Compute P: + result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol); + if(p_derivative) + *p_derivative = result; + if(result != 0) + result *= detail::lower_gamma_series(a, x, pol) / a; + } + else + { + // Compute Q: + invert = !invert; + result = tgamma_small_upper_part(a, x, pol); + if(normalised) + result /= boost::math::tgamma(a, pol); + if(p_derivative) + *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type()); + } + } + else if(x < 1.1) + { + // + // Changover here occurs when P ~ 0.6 or Q ~ 0.4: + // + if(x * 1.1f < a) + { + // Compute P: + result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol); + if(p_derivative) + *p_derivative = result; + if(result != 0) + result *= detail::lower_gamma_series(a, x, pol) / a; + } + else + { + // Compute Q: + invert = !invert; + result = tgamma_small_upper_part(a, x, pol); + if(normalised) + result /= boost::math::tgamma(a, pol); + if(p_derivative) + *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type()); + } + } + else + { + // + // Begin by testing whether we're in the "bad" zone + // where the result will be near 0.5 and the usual + // series and continued fractions are slow to converge: + // + bool use_temme = false; + if(normalised && std::numeric_limits::is_specialized && (a > 20)) + { + T sigma = fabs((x-a)/a); + if((a > 200) && (policies::digits() <= 113)) + { + // + // This limit is chosen so that we use Temme's expansion + // only if the result would be larger than about 10^-6. + // Below that the regular series and continued fractions + // converge OK, and if we use Temme's method we get increasing + // errors from the dominant erfc term as it's (inexact) argument + // increases in magnitude. + // + if(20 / a > sigma * sigma) + use_temme = true; + } + else if(policies::digits() <= 64) + { + // Note in this zone we can't use Temme's expansion for + // types longer than an 80-bit real: + // it would require too many terms in the polynomials. + if(sigma < 0.4) + use_temme = true; + } + } + if(use_temme) + { + // + // Use compile time dispatch to the appropriate + // Temme asymptotic expansion. This may be dead code + // if T does not have numeric limits support, or has + // too many digits for the most precise version of + // these expansions, in that case we'll be calling + // an empty function. + // + typedef typename policies::precision::type precision_type; + + typedef typename mpl::if_< + mpl::or_ >, + mpl::greater > >, + mpl::int_<0>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<53>, + typename mpl::if_< + mpl::less_equal >, + mpl::int_<64>, + mpl::int_<113> + >::type + >::type + >::type tag_type; + + result = igamma_temme_large(a, x, pol, static_cast(0)); + if(x >= a) + invert = !invert; + if(p_derivative) + *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type()); + } + else + { + // + // Regular case where the result will not be too close to 0.5. + // + // Changeover here occurs at P ~ Q ~ 0.5 + // + result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol); + if(p_derivative) + *p_derivative = result; + if(x < a) + { + // Compute P: + if(result != 0) + result *= detail::lower_gamma_series(a, x, pol) / a; + } + else + { + // Compute Q: + invert = !invert; + if(result != 0) + result *= upper_gamma_fraction(a, x, policies::digits()); + } + } + } + + if(invert) + { + T gam = normalised ? 1 : boost::math::tgamma(a, pol); + result = gam - result; + } + if(p_derivative) + { + // + // Need to convert prefix term to derivative: + // + if((x < 1) && (tools::max_value() * x < *p_derivative)) + { + // overflow, just return an arbitrarily large value: + *p_derivative = tools::max_value() / 2; + } + + *p_derivative /= x; + } + + return result; +} + +// +// Ratios of two gamma functions: +// +template +T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const L&) +{ + BOOST_MATH_STD_USING + T zgh = z + L::g() - constants::half(); + T result; + if(fabs(delta) < 10) + { + result = exp((constants::half() - z) * boost::math::log1p(delta / zgh, pol)); + } + else + { + result = pow(zgh / (zgh + delta), z - constants::half()); + } + result *= pow(constants::e() / (zgh + delta), delta); + result *= L::lanczos_sum(z) / L::lanczos_sum(z + delta); + return result; +} +// +// And again without Lanczos support this time: +// +template +T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const lanczos::undefined_lanczos&) +{ + BOOST_MATH_STD_USING + // + // The upper gamma fraction is *very* slow for z < 6, actually it's very + // slow to converge everywhere but recursing until z > 6 gets rid of the + // worst of it's behaviour. + // + T prefix = 1; + T zd = z + delta; + while((zd < 6) && (z < 6)) + { + prefix /= z; + prefix *= zd; + z += 1; + zd += 1; + } + if(delta < 10) + { + prefix *= exp(-z * boost::math::log1p(delta / z, pol)); + } + else + { + prefix *= pow(z / zd, z); + } + prefix *= pow(constants::e() / zd, delta); + T sum = detail::lower_gamma_series(z, z, pol) / z; + sum += detail::upper_gamma_fraction(z, z, ::boost::math::policies::digits()); + T sumd = detail::lower_gamma_series(zd, zd, pol) / zd; + sumd += detail::upper_gamma_fraction(zd, zd, ::boost::math::policies::digits()); + sum /= sumd; + if(fabs(tools::max_value() / prefix) < fabs(sum)) + return policies::raise_overflow_error("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Result of tgamma is too large to represent.", pol); + return sum * prefix; +} + +template +T tgamma_delta_ratio_imp(T z, T delta, const Policy& pol) +{ + BOOST_MATH_STD_USING + + if(z <= 0) + policies::raise_domain_error("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got a=%1%).", z, pol); + if(z+delta <= 0) + policies::raise_domain_error("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got b=%1%).", z+delta, pol); + + if(floor(delta) == delta) + { + if(floor(z) == z) + { + // + // Both z and delta are integers, see if we can just use table lookup + // of the factorials to get the result: + // + if((z <= max_factorial::value) && (z + delta <= max_factorial::value)) + { + return unchecked_factorial(tools::real_cast(z) - 1) / unchecked_factorial(tools::real_cast(z + delta) - 1); + } + } + if(fabs(delta) < 20) + { + // + // delta is a small integer, we can use a finite product: + // + if(delta == 0) + return 1; + if(delta < 0) + { + z -= 1; + T result = z; + while(0 != (delta += 1)) + { + z -= 1; + result *= z; + } + return result; + } + else + { + T result = 1 / z; + while(0 != (delta -= 1)) + { + z += 1; + result /= z; + } + return result; + } + } + } + typedef typename lanczos::lanczos::type lanczos_type; + return tgamma_delta_ratio_imp_lanczos(z, delta, pol, lanczos_type()); +} + +template +T gamma_p_derivative_imp(T a, T x, const Policy& pol) +{ + // + // Usual error checks first: + // + if(a <= 0) + policies::raise_domain_error("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol); + if(x < 0) + policies::raise_domain_error("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol); + // + // Now special cases: + // + if(x == 0) + { + return (a > 1) ? 0 : + (a == 1) ? 1 : policies::raise_overflow_error("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", 0, pol); + } + // + // Normal case: + // + typedef typename lanczos::lanczos::type lanczos_type; + T f1 = detail::regularised_gamma_prefix(a, x, pol, lanczos_type()); + if((x < 1) && (tools::max_value() * x < f1)) + { + // overflow: + return policies::raise_overflow_error("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", 0, pol); + } + + f1 /= x; + + return f1; +} + +template +inline typename tools::promote_args::type + tgamma(T z, const Policy& /* pol */, const mpl::true_) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + return policies::checked_narrowing_cast(detail::gamma_imp(static_cast(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma<%1%>(%1%)"); +} + +template +inline typename tools::promote_args::type + tgamma(T1 a, T2 z, const Policy& pol, const mpl::false_) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + return policies::checked_narrowing_cast( + detail::gamma_incomplete_imp(static_cast(a), + static_cast(z), false, true, + forwarding_policy(), static_cast(0)), "boost::math::tgamma<%1%>(%1%, %1%)"); +} + +template +inline typename tools::promote_args::type + tgamma(T1 a, T2 z, const mpl::false_ tag) +{ + return tgamma(a, z, policies::policy<>(), tag); +} + +} // namespace detail + +template +inline typename tools::promote_args::type + tgamma(T z) +{ + return tgamma(z, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + lgamma(T z, int* sign, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + return policies::checked_narrowing_cast(detail::lgamma_imp(static_cast(z), forwarding_policy(), evaluation_type(), sign), "boost::math::lgamma<%1%>(%1%)"); +} + +template +inline typename tools::promote_args::type + lgamma(T z, int* sign) +{ + return lgamma(z, sign, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + lgamma(T x, const Policy& pol) +{ + return ::boost::math::lgamma(x, 0, pol); +} + +template +inline typename tools::promote_args::type + lgamma(T x) +{ + return ::boost::math::lgamma(x, 0, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + tgamma1pm1(T z, const Policy& /* pol */) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast::type, forwarding_policy>(detail::tgammap1m1_imp(static_cast(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma1pm1<%!%>(%1%)"); +} + +template +inline typename tools::promote_args::type + tgamma1pm1(T z) +{ + return tgamma1pm1(z, policies::policy<>()); +} + +// +// Full upper incomplete gamma: +// +template +inline typename tools::promote_args::type + tgamma(T1 a, T2 z) +{ + // + // Type T2 could be a policy object, or a value, select the + // right overload based on T2: + // + typedef typename policies::is_policy::type maybe_policy; + return detail::tgamma(a, z, maybe_policy()); +} +template +inline typename tools::promote_args::type + tgamma(T1 a, T2 z, const Policy& pol) +{ + return detail::tgamma(a, z, pol, mpl::false_()); +} +// +// Full lower incomplete gamma: +// +template +inline typename tools::promote_args::type + tgamma_lower(T1 a, T2 z, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast( + detail::gamma_incomplete_imp(static_cast(a), + static_cast(z), false, false, + forwarding_policy(), static_cast(0)), "tgamma_lower<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + tgamma_lower(T1 a, T2 z) +{ + return tgamma_lower(a, z, policies::policy<>()); +} +// +// Regularised upper incomplete gamma: +// +template +inline typename tools::promote_args::type + gamma_q(T1 a, T2 z, const Policy& /* pol */) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast( + detail::gamma_incomplete_imp(static_cast(a), + static_cast(z), true, true, + forwarding_policy(), static_cast(0)), "gamma_q<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + gamma_q(T1 a, T2 z) +{ + return gamma_q(a, z, policies::policy<>()); +} +// +// Regularised lower incomplete gamma: +// +template +inline typename tools::promote_args::type + gamma_p(T1 a, T2 z, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename lanczos::lanczos::type evaluation_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast( + detail::gamma_incomplete_imp(static_cast(a), + static_cast(z), true, false, + forwarding_policy(), static_cast(0)), "gamma_p<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + gamma_p(T1 a, T2 z) +{ + return gamma_p(a, z, policies::policy<>()); +} + +// ratios of gamma functions: +template +inline typename tools::promote_args::type + tgamma_delta_ratio(T1 z, T2 delta, const Policy& /* pol */) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::tgamma_delta_ratio_imp(static_cast(z), static_cast(delta), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + tgamma_delta_ratio(T1 z, T2 delta) +{ + return tgamma_delta_ratio(z, delta, policies::policy<>()); +} +template +inline typename tools::promote_args::type + tgamma_ratio(T1 a, T2 b, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::tgamma_delta_ratio_imp(static_cast(a), static_cast(b) - static_cast(a), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + tgamma_ratio(T1 a, T2 b) +{ + return tgamma_ratio(a, b, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + gamma_p_derivative(T1 a, T2 x, const Policy& pol) +{ + BOOST_FPU_EXCEPTION_GUARD + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + return policies::checked_narrowing_cast(detail::gamma_p_derivative_imp(static_cast(a), static_cast(x), forwarding_policy()), "boost::math::gamma_p_derivative<%1%>(%1%, %1%)"); +} +template +inline typename tools::promote_args::type + gamma_p_derivative(T1 a, T2 x) +{ + return gamma_p_derivative(a, x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#include +#include +#include + +#endif // BOOST_MATH_SF_GAMMA_HPP + + + diff --git a/include/boost/math/special_functions/hermite.hpp b/include/boost/math/special_functions/hermite.hpp new file mode 100644 index 000000000..39c297a5b --- /dev/null +++ b/include/boost/math/special_functions/hermite.hpp @@ -0,0 +1,71 @@ + +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_HERMITE_HPP +#define BOOST_MATH_SPECIAL_HERMITE_HPP + +#include +#include +#include + +namespace boost{ +namespace math{ + +// Recurrance relation for Hermite polynomials: +template +inline typename tools::promote_args::type + hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1) +{ + return (2 * x * Hn - 2 * n * Hnm1); +} + +namespace detail{ + +// Implement Hermite polynomials via recurrance: +template +T hermite_imp(unsigned n, T x) +{ + T p0 = 1; + T p1 = 2 * x; + + if(n == 0) + return p0; + + unsigned c = 1; + + while(c < n) + { + std::swap(p0, p1); + p1 = hermite_next(c, x, p0, p1); + ++c; + } + return p1; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + hermite(unsigned n, T x, const Policy&) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::hermite_imp(n, static_cast(x)), "boost::math::hermite<%1%>(unsigned, %1%)"); +} + +template +inline typename tools::promote_args::type + hermite(unsigned n, T x) +{ + return boost::math::hermite(n, x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_HERMITE_HPP + + diff --git a/include/boost/math/special_functions/hypot.hpp b/include/boost/math/special_functions/hypot.hpp index c827692b3..ba97b9937 100644 --- a/include/boost/math/special_functions/hypot.hpp +++ b/include/boost/math/special_functions/hypot.hpp @@ -1,4 +1,4 @@ -// (C) Copyright John Maddock 2005. +// (C) Copyright John Maddock 2005-2006. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -6,79 +6,76 @@ #ifndef BOOST_MATH_HYPOT_INCLUDED #define BOOST_MATH_HYPOT_INCLUDED +#include +#include +#include +#include #include -#include -#include // swap - -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS -# include -#else -# include -#endif +#include // for swap #ifdef BOOST_NO_STDC_NAMESPACE namespace std{ using ::sqrt; using ::fabs; } #endif +namespace boost{ namespace math{ namespace detail{ -namespace boost{ namespace math{ - -template -T hypot(T x, T y) +template +T hypot_imp(T x, T y, const Policy& pol) { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(::std::numeric_limits::is_specialized); -#else - BOOST_ASSERT(std::numeric_limits::is_specialized); + // + // Normalize x and y, so that both are positive and x >= y: + // + using std::fabs; using std::sqrt; // ADL of std names + + x = fabs(x); + y = fabs(y); + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4127) #endif - - // - // normalize x and y, so that both are positive and x >= y: - // - x = (std::fabs)(x); - y = (std::fabs)(y); - // special case, see C99 Annex F: if(std::numeric_limits::has_infinity && ((x == std::numeric_limits::infinity()) || (y == std::numeric_limits::infinity()))) - return std::numeric_limits::infinity(); + return policies::raise_overflow_error("boost::math::hypot<%1%>(%1%,%1%)", 0, pol); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif - if(y > x) + if(y > x) (std::swap)(x, y); - // - // figure out overflow and underflow limits: - // - T safe_upper = (std::sqrt)((std::numeric_limits::max)()) / 2; - T safe_lower = (std::sqrt)((std::numeric_limits::min)()); - static const T one = 1; - // - // Now handle special cases: - // - if(x >= safe_upper) - { - if(y <= one) - { - // y is neligible: - return x; - } - return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x); - } - else if(y <= safe_lower) - { - if((x >= one) || (y == 0)) - { - // y is negligible: - return x; - } - return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x); - } - // - // If we get here then x^2+y^2 will not overflow or underflow: - // - return (std::sqrt)(x*x + y*y); + + if(x * tools::epsilon() >= y) + return x; + + T rat = y / x; + return x * sqrt(1 + rat*rat); +} // template T hypot(T x, T y) + } -} } // namespaces +template +inline typename tools::promote_args::type + hypot(T1 x, T2 y) +{ + typedef typename tools::promote_args::type result_type; + return detail::hypot_imp( + static_cast(x), static_cast(y), policies::policy<>()); +} + +template +inline typename tools::promote_args::type + hypot(T1 x, T2 y, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::hypot_imp( + static_cast(x), static_cast(y), pol); +} + +} // namespace math +} // namespace boost #endif // BOOST_MATH_HYPOT_INCLUDED + + diff --git a/include/boost/math/special_functions/laguerre.hpp b/include/boost/math/special_functions/laguerre.hpp new file mode 100644 index 000000000..d41eafaad --- /dev/null +++ b/include/boost/math/special_functions/laguerre.hpp @@ -0,0 +1,134 @@ + +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_LAGUERRE_HPP +#define BOOST_MATH_SPECIAL_LAGUERRE_HPP + +#include +#include +#include + +namespace boost{ +namespace math{ + +// Recurrance relation for Laguerre polynomials: +template +inline typename tools::promote_args::type + laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1) +{ + typedef typename tools::promote_args::type result_type; + return ((2 * n + 1 - result_type(x)) * result_type(Ln) - n * result_type(Lnm1)) / (n + 1); +} + +namespace detail{ + +// Implement Laguerre polynomials via recurrance: +template +T laguerre_imp(unsigned n, T x) +{ + T p0 = 1; + T p1 = 1 - x; + + if(n == 0) + return p0; + + unsigned c = 1; + + while(c < n) + { + std::swap(p0, p1); + p1 = laguerre_next(c, x, p0, p1); + ++c; + } + return p1; +} + +template +inline typename tools::promote_args::type +laguerre(unsigned n, T x, const Policy&, const mpl::true_&) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::laguerre_imp(n, static_cast(x)), "boost::math::laguerre<%1%>(unsigned, %1%)"); +} + +template +inline typename tools::promote_args::type + laguerre(unsigned n, unsigned m, T x, const mpl::false_&) +{ + return boost::math::laguerre(n, m, x, policies::policy<>()); +} + +} // namespace detail + +template +inline typename tools::promote_args::type + laguerre(unsigned n, T x) +{ + return laguerre(n, x, policies::policy<>()); +} + +// Recurrence for associated polynomials: +template +inline typename tools::promote_args::type + laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1) +{ + typedef typename tools::promote_args::type result_type; + return ((2 * n + l + 1 - result_type(x)) * result_type(Pl) - (n + l) * result_type(Plm1)) / (n+1); +} + +namespace detail{ +// Laguerre Associated Polynomial: +template +T laguerre_imp(unsigned n, unsigned m, T x, const Policy& pol) +{ + // Special cases: + if(m == 0) + return boost::math::laguerre(n, x, pol); + + T p0 = 1; + + if(n == 0) + return p0; + + T p1 = m + 1 - x; + + unsigned c = 1; + + while(c < n) + { + std::swap(p0, p1); + p1 = laguerre_next(c, m, x, p0, p1); + ++c; + } + return p1; +} + +} + +template +inline typename tools::promote_args::type + laguerre(unsigned n, unsigned m, T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::laguerre_imp(n, m, static_cast(x), pol), "boost::math::laguerre<%1%>(unsigned, unsigned, %1%)"); +} + +template +inline typename laguerre_result::type + laguerre(unsigned n, T1 m, T2 x) +{ + typedef typename policies::is_policy::type tag_type; + return detail::laguerre(n, m, x, tag_type()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_LAGUERRE_HPP + + diff --git a/include/boost/math/special_functions/lanczos.hpp b/include/boost/math/special_functions/lanczos.hpp new file mode 100644 index 000000000..2f984f615 --- /dev/null +++ b/include/boost/math/special_functions/lanczos.hpp @@ -0,0 +1,1231 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS +#define BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost{ namespace math{ namespace lanczos{ + +// +// Individual lanczos approximations start here. +// +// Optimal values for G for each N are taken from +// http://web.mala.bc.ca/pughg/phdThesis/phdThesis.pdf, +// as are the theoretical error bounds. +// +// Constants calculated using the method described by Godfrey +// http://my.fit.edu/~gabdo/gamma.txt and elaborated by Toth at +// http://www.rskey.org/gamma.htm using NTL::RR at 1000 bit precision. +// +// Lanczos Coefficients for N=6 G=5.581 +// Max experimental error (with arbitary precision arithmetic) 9.516e-12 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos6 : public mpl::int_<35> +{ + // + // Produces slightly better than float precision when evaluated at + // double precision: + // + template + static T lanczos_sum(const T& z) + { + static const T num[6] = { + static_cast(8706.349592549009182288174442774377925882L), + static_cast(8523.650341121874633477483696775067709735L), + static_cast(3338.029219476423550899999750161289306564L), + static_cast(653.6424994294008795995653541449610986791L), + static_cast(63.99951844938187085666201263218840287667L), + static_cast(2.506628274631006311133031631822390264407L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = { + static_cast(0u), + static_cast(24u), + static_cast(50u), + static_cast(35u), + static_cast(10u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[6] = { + static_cast(32.81244541029783471623665933780748627823L), + static_cast(32.12388941444332003446077108933558534361L), + static_cast(12.58034729455216106950851080138931470954L), + static_cast(2.463444478353241423633780693218408889251L), + static_cast(0.2412010548258800231126240760264822486599L), + static_cast(0.009446967704539249494420221613134244048319L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = { + static_cast(0u), + static_cast(24u), + static_cast(50u), + static_cast(35u), + static_cast(10u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[5] = { + static_cast(2.044879010930422922760429926121241330235L), + static_cast(-2.751366405578505366591317846728753993668L), + static_cast(1.02282965224225004296750609604264824677L), + static_cast(-0.09786124911582813985028889636665335893627L), + static_cast(0.0009829742267506615183144364420540766510112L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[5] = { + static_cast(5.748142489536043490764289256167080091892L), + static_cast(-7.734074268282457156081021756682138251825L), + static_cast(2.875167944990511006997713242805893543947L), + static_cast(-0.2750873773533504542306766137703788781776L), + static_cast(0.002763134585812698552178368447708846850353L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 5.581000000000000405009359383257105946541; } +}; + +// +// Lanczos Coefficients for N=11 G=10.900511 +// Max experimental error (with arbitary precision arithmetic) 2.16676e-19 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos11 : public mpl::int_<60> +{ + // + // Produces slightly better than double precision when evaluated at + // extended-double precision: + // + template + static T lanczos_sum(const T& z) + { + static const T num[11] = { + static_cast(38474670393.31776828316099004518914832218L), + static_cast(36857665043.51950660081971227404959150474L), + static_cast(15889202453.72942008945006665994637853242L), + static_cast(4059208354.298834770194507810788393801607L), + static_cast(680547661.1834733286087695557084801366446L), + static_cast(78239755.00312005289816041245285376206263L), + static_cast(6246580.776401795264013335510453568106366L), + static_cast(341986.3488721347032223777872763188768288L), + static_cast(12287.19451182455120096222044424100527629L), + static_cast(261.6140441641668190791708576058805625502L), + static_cast(2.506628274631000502415573855452633787834L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[11] = { + static_cast(0u), + static_cast(362880u), + static_cast(1026576u), + static_cast(1172700u), + static_cast(723680u), + static_cast(269325u), + static_cast(63273u), + static_cast(9450u), + static_cast(870u), + static_cast(45u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[11] = { + static_cast(709811.662581657956893540610814842699825L), + static_cast(679979.847415722640161734319823103390728L), + static_cast(293136.785721159725251629480984140341656L), + static_cast(74887.5403291467179935942448101441897121L), + static_cast(12555.29058241386295096255111537516768137L), + static_cast(1443.42992444170669746078056942194198252L), + static_cast(115.2419459613734722083208906727972935065L), + static_cast(6.30923920573262762719523981992008976989L), + static_cast(0.2266840463022436475495508977579735223818L), + static_cast(0.004826466289237661857584712046231435101741L), + static_cast(0.4624429436045378766270459638520555557321e-4L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[11] = { + static_cast(0u), + static_cast(362880u), + static_cast(1026576u), + static_cast(1172700u), + static_cast(723680u), + static_cast(269325u), + static_cast(63273u), + static_cast(9450u), + static_cast(870u), + static_cast(45u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[10] = { + static_cast(4.005853070677940377969080796551266387954L), + static_cast(-13.17044315127646469834125159673527183164L), + static_cast(17.19146865350790353683895137079288129318L), + static_cast(-11.36446409067666626185701599196274701126L), + static_cast(4.024801119349323770107694133829772634737L), + static_cast(-0.7445703262078094128346501724255463005006L), + static_cast(0.06513861351917497265045550019547857713172L), + static_cast(-0.00217899958561830354633560009312512312758L), + static_cast(0.17655204574495137651670832229571934738e-4L), + static_cast(-0.1036282091079938047775645941885460820853e-7L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[10] = { + static_cast(19.05889633808148715159575716844556056056L), + static_cast(-62.66183664701721716960978577959655644762L), + static_cast(81.7929198065004751699057192860287512027L), + static_cast(-54.06941772964234828416072865069196553015L), + static_cast(19.14904664790693019642068229478769661515L), + static_cast(-3.542488556926667589704590409095331790317L), + static_cast(0.3099140334815639910894627700232804503017L), + static_cast(-0.01036716187296241640634252431913030440825L), + static_cast(0.8399926504443119927673843789048514017761e-4L), + static_cast(-0.493038376656195010308610694048822561263e-7L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 10.90051099999999983936049829935654997826; } +}; + +// +// Lanczos Coefficients for N=13 G=13.144565 +// Max experimental error (with arbitary precision arithmetic) 9.2213e-23 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos13 : public mpl::int_<72> +{ + // + // Produces slightly better than extended-double precision when evaluated at + // higher precision: + // + template + static T lanczos_sum(const T& z) + { + static const T num[13] = { + static_cast(44012138428004.60895436261759919070125699L), + static_cast(41590453358593.20051581730723108131357995L), + static_cast(18013842787117.99677796276038389462742949L), + static_cast(4728736263475.388896889723995205703970787L), + static_cast(837910083628.4046470415724300225777912264L), + static_cast(105583707273.4299344907359855510105321192L), + static_cast(9701363618.494999493386608345339104922694L), + static_cast(654914397.5482052641016767125048538245644L), + static_cast(32238322.94213356530668889463945849409184L), + static_cast(1128514.219497091438040721811544858643121L), + static_cast(26665.79378459858944762533958798805525125L), + static_cast(381.8801248632926870394389468349331394196L), + static_cast(2.506628274631000502415763426076722427007L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = { + static_cast(0u), + static_cast(39916800u), + static_cast(120543840u), + static_cast(150917976u), + static_cast(105258076u), + static_cast(45995730u), + static_cast(13339535u), + static_cast(2637558u), + static_cast(357423u), + static_cast(32670u), + static_cast(1925u), + static_cast(66u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[13] = { + static_cast(86091529.53418537217994842267760536134841L), + static_cast(81354505.17858011242874285785316135398567L), + static_cast(35236626.38815461910817650960734605416521L), + static_cast(9249814.988024471294683815872977672237195L), + static_cast(1639024.216687146960253839656643518985826L), + static_cast(206530.8157641225032631778026076868855623L), + static_cast(18976.70193530288915698282139308582105936L), + static_cast(1281.068909912559479885759622791374106059L), + static_cast(63.06093343420234536146194868906771599354L), + static_cast(2.207470909792527638222674678171050209691L), + static_cast(0.05216058694613505427476207805814960742102L), + static_cast(0.0007469903808915448316510079585999893674101L), + static_cast(0.4903180573459871862552197089738373164184e-5L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = { + static_cast(0u), + static_cast(39916800u), + static_cast(120543840u), + static_cast(150917976u), + static_cast(105258076u), + static_cast(45995730u), + static_cast(13339535u), + static_cast(2637558u), + static_cast(357423u), + static_cast(32670u), + static_cast(1925u), + static_cast(66u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[12] = { + static_cast(4.832115561461656947793029596285626840312L), + static_cast(-19.86441536140337740383120735104359034688L), + static_cast(33.9927422807443239927197864963170585331L), + static_cast(-31.41520692249765980987427413991250886138L), + static_cast(17.0270866009599345679868972409543597821L), + static_cast(-5.5077216950865501362506920516723682167L), + static_cast(1.037811741948214855286817963800439373362L), + static_cast(-0.106640468537356182313660880481398642811L), + static_cast(0.005276450526660653288757565778182586742831L), + static_cast(-0.0001000935625597121545867453746252064770029L), + static_cast(0.462590910138598083940803704521211569234e-6L), + static_cast(-0.1735307814426389420248044907765671743012e-9L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[12] = { + static_cast(26.96979819614830698367887026728396466395L), + static_cast(-110.8705424709385114023884328797900204863L), + static_cast(189.7258846119231466417015694690434770085L), + static_cast(-175.3397202971107486383321670769397356553L), + static_cast(95.03437648691551457087250340903980824948L), + static_cast(-30.7406022781665264273675797983497141978L), + static_cast(5.792405601630517993355102578874590410552L), + static_cast(-0.5951993240669148697377539518639997795831L), + static_cast(0.02944979359164017509944724739946255067671L), + static_cast(-0.0005586586555377030921194246330399163602684L), + static_cast(0.2581888478270733025288922038673392636029e-5L), + static_cast(-0.9685385411006641478305219367315965391289e-9L), + }; + T result = 0; + T z = z = 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 13.1445650000000000545696821063756942749; } +}; + +// +// Lanczos Coefficients for N=22 G=22.61891 +// Max experimental error (with arbitary precision arithmetic) 2.9524e-38 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos22 : public mpl::int_<120> +{ + // + // Produces slightly better than 128-bit long-double precision when + // evaluated at higher precision: + // + template + static T lanczos_sum(const T& z) + { + static const T num[22] = { + static_cast(46198410803245094237463011094.12173081986L), + static_cast(43735859291852324413622037436.321513777L), + static_cast(19716607234435171720534556386.97481377748L), + static_cast(5629401471315018442177955161.245623932129L), + static_cast(1142024910634417138386281569.245580222392L), + static_cast(175048529315951173131586747.695329230778L), + static_cast(21044290245653709191654675.41581372963167L), + static_cast(2033001410561031998451380.335553678782601L), + static_cast(160394318862140953773928.8736211601848891L), + static_cast(10444944438396359705707.48957290388740896L), + static_cast(565075825801617290121.1466393747967538948L), + static_cast(25475874292116227538.99448534450411942597L), + static_cast(957135055846602154.6720835535232270205725L), + static_cast(29874506304047462.23662392445173880821515L), + static_cast(769651310384737.2749087590725764959689181L), + static_cast(16193289100889.15989633624378404096011797L), + static_cast(273781151680.6807433264462376754578933261L), + static_cast(3630485900.32917021712188739762161583295L), + static_cast(36374352.05577334277856865691538582936484L), + static_cast(258945.7742115532455441786924971194951043L), + static_cast(1167.501919472435718934219997431551246996L), + static_cast(2.50662827463100050241576528481104525333L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = { + (0uLL), + (2432902008176640000uLL), + (8752948036761600000uLL), + (13803759753640704000uLL), + (12870931245150988800uLL), + (8037811822645051776uLL), + (3599979517947607200uLL), + (1206647803780373360uLL), + (311333643161390640uLL), + (63030812099294896uLL), + (10142299865511450uLL), + (1307535010540395uLL), + (135585182899530uLL), + (11310276995381uLL), + (756111184500uLL), + (40171771630uLL), + (1672280820uLL), + (53327946uLL), + (1256850uLL), + (20615uLL), + (210uLL), + (1uLL) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[22] = { + static_cast(6939996264376682180.277485395074954356211L), + static_cast(6570067992110214451.87201438870245659384L), + static_cast(2961859037444440551.986724631496417064121L), + static_cast(845657339772791245.3541226499766163431651L), + static_cast(171556737035449095.2475716923888737881837L), + static_cast(26296059072490867.7822441885603400926007L), + static_cast(3161305619652108.433798300149816829198706L), + static_cast(305400596026022.4774396904484542582526472L), + static_cast(24094681058862.55120507202622377623528108L), + static_cast(1569055604375.919477574824168939428328839L), + static_cast(84886558909.02047889339710230696942513159L), + static_cast(3827024985.166751989686050643579753162298L), + static_cast(143782298.9273215199098728674282885500522L), + static_cast(4487794.24541641841336786238909171265944L), + static_cast(115618.2025760830513505888216285273541959L), + static_cast(2432.580773108508276957461757328744780439L), + static_cast(41.12782532742893597168530008461874360191L), + static_cast(0.5453771709477689805460179187388702295792L), + static_cast(0.005464211062612080347167337964166505282809L), + static_cast(0.388992321263586767037090706042788910953e-4L), + static_cast(0.1753839324538447655939518484052327068859e-6L), + static_cast(0.3765495513732730583386223384116545391759e-9L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = { + (0uLL), + (2432902008176640000uLL), + (8752948036761600000uLL), + (13803759753640704000uLL), + (12870931245150988800uLL), + (8037811822645051776uLL), + (3599979517947607200uLL), + (1206647803780373360uLL), + (311333643161390640uLL), + (63030812099294896uLL), + (10142299865511450uLL), + (1307535010540395uLL), + (135585182899530uLL), + (11310276995381uLL), + (756111184500uLL), + (40171771630uLL), + (1672280820uLL), + (53327946uLL), + (1256850uLL), + (20615uLL), + (210uLL), + (1uLL) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[21] = { + static_cast(8.318998691953337183034781139546384476554L), + static_cast(-63.15415991415959158214140353299240638675L), + static_cast(217.3108224383632868591462242669081540163L), + static_cast(-448.5134281386108366899784093610397354889L), + static_cast(619.2903759363285456927248474593012711346L), + static_cast(-604.1630177420625418522025080080444177046L), + static_cast(428.8166750424646119935047118287362193314L), + static_cast(-224.6988753721310913866347429589434550302L), + static_cast(87.32181627555510833499451817622786940961L), + static_cast(-25.07866854821128965662498003029199058098L), + static_cast(5.264398125689025351448861011657789005392L), + static_cast(-0.792518936256495243383586076579921559914L), + static_cast(0.08317448364744713773350272460937904691566L), + static_cast(-0.005845345166274053157781068150827567998882L), + static_cast(0.0002599412126352082483326238522490030412391L), + static_cast(-0.6748102079670763884917431338234783496303e-5L), + static_cast(0.908824383434109002762325095643458603605e-7L), + static_cast(-0.5299325929309389890892469299969669579725e-9L), + static_cast(0.994306085859549890267983602248532869362e-12L), + static_cast(-0.3499893692975262747371544905820891835298e-15L), + static_cast(0.7260746353663365145454867069182884694961e-20L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[21] = { + static_cast(75.39272007105208086018421070699575462226L), + static_cast(-572.3481967049935412452681346759966390319L), + static_cast(1969.426202741555335078065370698955484358L), + static_cast(-4064.74968778032030891520063865996757519L), + static_cast(5612.452614138013929794736248384309574814L), + static_cast(-5475.357667500026172903620177988213902339L), + static_cast(3886.243614216111328329547926490398103492L), + static_cast(-2036.382026072125407192448069428134470564L), + static_cast(791.3727954936062108045551843636692287652L), + static_cast(-227.2808432388436552794021219198885223122L), + static_cast(47.70974355562144229897637024320739257284L), + static_cast(-7.182373807798293545187073539819697141572L), + static_cast(0.7537866989631514559601547530490976100468L), + static_cast(-0.05297470142240154822658739758236594717787L), + static_cast(0.00235577330936380542539812701472320434133L), + static_cast(-0.6115613067659273118098229498679502138802e-4L), + static_cast(0.8236417010170941915758315020695551724181e-6L), + static_cast(-0.4802628430993048190311242611330072198089e-8L), + static_cast(0.9011113376981524418952720279739624707342e-11L), + static_cast(-0.3171854152689711198382455703658589996796e-14L), + static_cast(0.6580207998808093935798753964580596673177e-19L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 22.61890999999999962710717227309942245483; } +}; + +// +// Lanczos Coefficients for N=6 G=1.428456135094165802001953125 +// Max experimental error (with arbitary precision arithmetic) 8.111667e-8 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos6m24 : public mpl::int_<24> +{ + // + // Use for float precision, when evaluated as a float: + // + template + static T lanczos_sum(const T& z) + { + static const T num[6] = { + static_cast(58.52061591769095910314047740215847630266L), + static_cast(182.5248962595894264831189414768236280862L), + static_cast(211.0971093028510041839168287718170827259L), + static_cast(112.2526547883668146736465390902227161763L), + static_cast(27.5192015197455403062503721613097825345L), + static_cast(2.50662858515256974113978724717473206342L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = { + static_cast(0u), + static_cast(24u), + static_cast(50u), + static_cast(35u), + static_cast(10u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[6] = { + static_cast(14.0261432874996476619570577285003839357L), + static_cast(43.74732405540314316089531289293124360129L), + static_cast(50.59547402616588964511581430025589038612L), + static_cast(26.90456680562548195593733429204228910299L), + static_cast(6.595765571169314946316366571954421695196L), + static_cast(0.6007854010515290065101128585795542383721L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = { + static_cast(0u), + static_cast(24u), + static_cast(50u), + static_cast(35u), + static_cast(10u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[5] = { + static_cast(0.4922488055204602807654354732674868442106L), + static_cast(0.004954497451132152436631238060933905650346L), + static_cast(-0.003374784572167105840686977985330859371848L), + static_cast(0.001924276018962061937026396537786414831385L), + static_cast(-0.00056533046336427583708166383712907694434L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[5] = { + static_cast(0.6534966888520080645505805298901130485464L), + static_cast(0.006577461728560758362509168026049182707101L), + static_cast(-0.004480276069269967207178373559014835978161L), + static_cast(0.00255461870648818292376982818026706528842L), + static_cast(-0.000750517993690428370380996157470900204524L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 1.428456135094165802001953125; } +}; + +// +// Lanczos Coefficients for N=13 G=6.024680040776729583740234375 +// Max experimental error (with arbitary precision arithmetic) 1.196214e-17 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos13m53 : public mpl::int_<53> +{ + // + // Use for double precision, when evaluated as a double: + // + template + static T lanczos_sum(const T& z) + { + static const T num[13] = { + static_cast(23531376880.41075968857200767445163675473L), + static_cast(42919803642.64909876895789904700198885093L), + static_cast(35711959237.35566804944018545154716670596L), + static_cast(17921034426.03720969991975575445893111267L), + static_cast(6039542586.35202800506429164430729792107L), + static_cast(1439720407.311721673663223072794912393972L), + static_cast(248874557.8620541565114603864132294232163L), + static_cast(31426415.58540019438061423162831820536287L), + static_cast(2876370.628935372441225409051620849613599L), + static_cast(186056.2653952234950402949897160456992822L), + static_cast(8071.672002365816210638002902272250613822L), + static_cast(210.8242777515793458725097339207133627117L), + static_cast(2.506628274631000270164908177133837338626L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = { + static_cast(0u), + static_cast(39916800u), + static_cast(120543840u), + static_cast(150917976u), + static_cast(105258076u), + static_cast(45995730u), + static_cast(13339535u), + static_cast(2637558u), + static_cast(357423u), + static_cast(32670u), + static_cast(1925u), + static_cast(66u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[13] = { + static_cast(56906521.91347156388090791033559122686859L), + static_cast(103794043.1163445451906271053616070238554L), + static_cast(86363131.28813859145546927288977868422342L), + static_cast(43338889.32467613834773723740590533316085L), + static_cast(14605578.08768506808414169982791359218571L), + static_cast(3481712.15498064590882071018964774556468L), + static_cast(601859.6171681098786670226533699352302507L), + static_cast(75999.29304014542649875303443598909137092L), + static_cast(6955.999602515376140356310115515198987526L), + static_cast(449.9445569063168119446858607650988409623L), + static_cast(19.51992788247617482847860966235652136208L), + static_cast(0.5098416655656676188125178644804694509993L), + static_cast(0.006061842346248906525783753964555936883222L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = { + static_cast(0u), + static_cast(39916800u), + static_cast(120543840u), + static_cast(150917976u), + static_cast(105258076u), + static_cast(45995730u), + static_cast(13339535u), + static_cast(2637558u), + static_cast(357423u), + static_cast(32670u), + static_cast(1925u), + static_cast(66u), + static_cast(1u) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[12] = { + static_cast(2.208709979316623790862569924861841433016L), + static_cast(-3.327150580651624233553677113928873034916L), + static_cast(1.483082862367253753040442933770164111678L), + static_cast(-0.1993758927614728757314233026257810172008L), + static_cast(0.004785200610085071473880915854204301886437L), + static_cast(-0.1515973019871092388943437623825208095123e-5L), + static_cast(-0.2752907702903126466004207345038327818713e-7L), + static_cast(0.3075580174791348492737947340039992829546e-7L), + static_cast(-0.1933117898880828348692541394841204288047e-7L), + static_cast(0.8690926181038057039526127422002498960172e-8L), + static_cast(-0.2499505151487868335680273909354071938387e-8L), + static_cast(0.3394643171893132535170101292240837927725e-9L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[12] = { + static_cast(6.565936202082889535528455955485877361223L), + static_cast(-9.8907772644920670589288081640128194231L), + static_cast(4.408830289125943377923077727900630927902L), + static_cast(-0.5926941084905061794445733628891024027949L), + static_cast(0.01422519127192419234315002746252160965831L), + static_cast(-0.4506604409707170077136555010018549819192e-5L), + static_cast(-0.8183698410724358930823737982119474130069e-7L), + static_cast(0.9142922068165324132060550591210267992072e-7L), + static_cast(-0.5746670642147041587497159649318454348117e-7L), + static_cast(0.2583592566524439230844378948704262291927e-7L), + static_cast(-0.7430396708998719707642735577238449585822e-8L), + static_cast(0.1009141566987569892221439918230042368112e-8L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 6.024680040776729583740234375; } +}; + +// +// Lanczos Coefficients for N=17 G=12.2252227365970611572265625 +// Max experimental error (with arbitary precision arithmetic) 2.7699e-26 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos17m64 : public mpl::int_<64> +{ + // + // Use for extended-double precision, when evaluated as an extended-double: + // + template + static T lanczos_sum(const T& z) + { + static const T num[17] = { + static_cast(553681095419291969.2230556393350368550504L), + static_cast(731918863887667017.2511276782146694632234L), + static_cast(453393234285807339.4627124634539085143364L), + static_cast(174701893724452790.3546219631779712198035L), + static_cast(46866125995234723.82897281620357050883077L), + static_cast(9281280675933215.169109622777099699054272L), + static_cast(1403600894156674.551057997617468721789536L), + static_cast(165345984157572.7305349809894046783973837L), + static_cast(15333629842677.31531822808737907246817024L), + static_cast(1123152927963.956626161137169462874517318L), + static_cast(64763127437.92329018717775593533620578237L), + static_cast(2908830362.657527782848828237106640944457L), + static_cast(99764700.56999856729959383751710026787811L), + static_cast(2525791.604886139959837791244686290089331L), + static_cast(44516.94034970167828580039370201346554872L), + static_cast(488.0063567520005730476791712814838113252L), + static_cast(2.50662827463100050241576877135758834683L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = { + (0uLL), + (1307674368000uLL), + (4339163001600uLL), + (6165817614720uLL), + (5056995703824uLL), + (2706813345600uLL), + (1009672107080uLL), + (272803210680uLL), + (54631129553uLL), + (8207628000uLL), + (928095740uLL), + (78558480uLL), + (4899622uLL), + (218400uLL), + (6580uLL), + (120uLL), + (1uLL) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[17] = { + static_cast(2715894658327.717377557655133124376674911L), + static_cast(3590179526097.912105038525528721129550434L), + static_cast(2223966599737.814969312127353235818710172L), + static_cast(856940834518.9562481809925866825485883417L), + static_cast(229885871668.749072933597446453399395469L), + static_cast(45526171687.54610815813502794395753410032L), + static_cast(6884887713.165178784550917647709216424823L), + static_cast(811048596.1407531864760282453852372777439L), + static_cast(75213915.96540822314499613623119501704812L), + static_cast(5509245.417224265151697527957954952830126L), + static_cast(317673.5368435419126714931842182369574221L), + static_cast(14268.27989845035520147014373320337523596L), + static_cast(489.3618720403263670213909083601787814792L), + static_cast(12.38941330038454449295883217865458609584L), + static_cast(0.2183627389504614963941574507281683147897L), + static_cast(0.002393749522058449186690627996063983095463L), + static_cast(0.1229541408909435212800785616808830746135e-4L) + }; + static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = { + (0uLL), + (1307674368000uLL), + (4339163001600uLL), + (6165817614720uLL), + (5056995703824uLL), + (2706813345600uLL), + (1009672107080uLL), + (272803210680uLL), + (54631129553uLL), + (8207628000uLL), + (928095740uLL), + (78558480uLL), + (4899622uLL), + (218400uLL), + (6580uLL), + (120uLL), + (1uLL) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[16] = { + static_cast(4.493645054286536365763334986866616581265L), + static_cast(-16.95716370392468543800733966378143997694L), + static_cast(26.19196892983737527836811770970479846644L), + static_cast(-21.3659076437988814488356323758179283908L), + static_cast(9.913992596774556590710751047594507535764L), + static_cast(-2.62888300018780199210536267080940382158L), + static_cast(0.3807056693542503606384861890663080735588L), + static_cast(-0.02714647489697685807340312061034730486958L), + static_cast(0.0007815484715461206757220527133967191796747L), + static_cast(-0.6108630817371501052576880554048972272435e-5L), + static_cast(0.5037380238864836824167713635482801545086e-8L), + static_cast(-0.1483232144262638814568926925964858237006e-13L), + static_cast(0.1346609158752142460943888149156716841693e-14L), + static_cast(-0.660492688923978805315914918995410340796e-15L), + static_cast(0.1472114697343266749193617793755763792681e-15L), + static_cast(-0.1410901942033374651613542904678399264447e-16L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[16] = { + static_cast(23.56409085052261327114594781581930373708L), + static_cast(-88.92116338946308797946237246006238652361L), + static_cast(137.3472822086847596961177383569603988797L), + static_cast(-112.0400438263562152489272966461114852861L), + static_cast(51.98768915202973863076166956576777843805L), + static_cast(-13.78552090862799358221343319574970124948L), + static_cast(1.996371068830872830250406773917646121742L), + static_cast(-0.1423525874909934506274738563671862576161L), + static_cast(0.004098338646046865122459664947239111298524L), + static_cast(-0.3203286637326511000882086573060433529094e-4L), + static_cast(0.2641536751640138646146395939004587594407e-7L), + static_cast(-0.7777876663062235617693516558976641009819e-13L), + static_cast(0.7061443477097101636871806229515157914789e-14L), + static_cast(-0.3463537849537988455590834887691613484813e-14L), + static_cast(0.7719578215795234036320348283011129450595e-15L), + static_cast(-0.7398586479708476329563577384044188912075e-16L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 12.2252227365970611572265625; } +}; + +// +// Lanczos Coefficients for N=24 G=20.3209821879863739013671875 +// Max experimental error (with arbitary precision arithmetic) 1.0541e-38 +// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006 +// +struct lanczos24m113 : public mpl::int_<113> +{ + // + // Use for long-double precision, when evaluated as an long-double: + // + template + static T lanczos_sum(const T& z) + { + static const T num[24] = { + static_cast(2029889364934367661624137213253.22102954656825019111612712252027267955023987678816620961507L), + static_cast(2338599599286656537526273232565.2727349714338768161421882478417543004440597874814359063158L), + static_cast(1288527989493833400335117708406.3953711906175960449186720680201425446299360322830739180195L), + static_cast(451779745834728745064649902914.550539158066332484594436145043388809847364393288132164411521L), + static_cast(113141284461097964029239556815.291212318665536114012605167994061291631013303788706545334708L), + static_cast(21533689802794625866812941616.7509064680880468667055339259146063256555368135236149614592432L), + static_cast(3235510315314840089932120340.71494940111731241353655381919722177496659303550321056514776757L), + static_cast(393537392344185475704891959.081297108513472083749083165179784098220158201055270548272414314L), + static_cast(39418265082950435024868801.5005452240816902251477336582325944930252142622315101857742955673L), + static_cast(3290158764187118871697791.05850632319194734270969161036889516414516566453884272345518372696L), + static_cast(230677110449632078321772.618245845856640677845629174549731890660612368500786684333975350954L), + static_cast(13652233645509183190158.5916189185218250859402806777406323001463296297553612462737044693697L), + static_cast(683661466754325350495.216655026531202476397782296585200982429378069417193575896602446904762L), + static_cast(28967871782219334117.0122379171041074970463982134039409352925258212207710168851968215545064L), + static_cast(1036104088560167006.2022834098572346459442601718514554488352117620272232373622553429728555L), + static_cast(31128490785613152.8380102669349814751268126141105475287632676569913936040772990253369753962L), + static_cast(779327504127342.536207878988196814811198475410572992436243686674896894543126229424358472541L), + static_cast(16067543181294.643350688789124777020407337133926174150582333950666044399234540521336771876L), + static_cast(268161795520.300916569439413185778557212729611517883948634711190170998896514639936969855484L), + static_cast(3533216359.10528191668842486732408440112703691790824611391987708562111396961696753452085068L), + static_cast(35378979.5479656110614685178752543826919239614088343789329169535932709470588426584501652577L), + static_cast(253034.881362204346444503097491737872930637147096453940375713745904094735506180552724766444L), + static_cast(1151.61895453463992438325318456328526085882924197763140514450975619271382783957699017875304L), + static_cast(2.50662827463100050241576528481104515966515623051532908941425544355490413900497467936202516L) + }; + static const T denom[24] = { + static_cast(0L), + static_cast(0.112400072777760768e22L), + static_cast(0.414847677933545472e22L), + static_cast(6756146673770930688000.0L), + static_cast(6548684852703068697600.0L), + static_cast(4280722865357147142912.0L), + static_cast(2021687376910682741568.0L), + static_cast(720308216440924653696.0L), + static_cast(199321978221066137360.0L), + static_cast(43714229649594412832.0L), + static_cast(7707401101297361068.0L), + static_cast(1103230881185949736.0L), + static_cast(129006659818331295.0L), + static_cast(12363045847086207.0L), + static_cast(971250460939913.0L), + static_cast(62382416421941.0L), + static_cast(3256091103430.0L), + static_cast(136717357942.0L), + static_cast(4546047198.0L), + static_cast(116896626L), + static_cast(2240315L), + static_cast(30107L), + static_cast(253L), + static_cast(1L) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + template + static T lanczos_sum_expG_scaled(const T& z) + { + static const T num[24] = { + static_cast(3035162425359883494754.02878223286972654682199012688209026810841953293372712802258398358538L), + static_cast(3496756894406430103600.16057175075063458536101374170860226963245118484234495645518505519827L), + static_cast(1926652656689320888654.01954015145958293168365236755537645929361841917596501251362171653478L), + static_cast(675517066488272766316.083023742440619929434602223726894748181327187670231286180156444871912L), + static_cast(169172853104918752780.086262749564831660238912144573032141700464995906149421555926000038492L), + static_cast(32197935167225605785.6444116302160245528783954573163541751756353183343357329404208062043808L), + static_cast(4837849542714083249.37587447454818124327561966323276633775195138872820542242539845253171632L), + static_cast(588431038090493242.308438203986649553459461798968819276505178004064031201740043314534404158L), + static_cast(58939585141634058.6206417889192563007809470547755357240808035714047014324843817783741669733L), + static_cast(4919561837722192.82991866530802080996138070630296720420704876654726991998309206256077395868L), + static_cast(344916580244240.407442753122831512004021081677987651622305356145640394384006997569631719101L), + static_cast(20413302960687.8250598845969238472629322716685686993835561234733641729957841485003560103066L), + static_cast(1022234822943.78400752460970689311934727763870970686747383486600540378889311406851534545789L), + static_cast(43313787191.9821354846952908076307094286897439975815501673706144217246093900159173598852503L), + static_cast(1549219505.59667418528481770869280437577581951167003505825834192510436144666564648361001914L), + static_cast(46544421.1998761919380541579358096705925369145324466147390364674998568485110045455014967149L), + static_cast(1165278.06807504975090675074910052763026564833951579556132777702952882101173607903881127542L), + static_cast(24024.759267256769471083727721827405338569868270177779485912486668586611981795179894572115L), + static_cast(400.965008113421955824358063769761286758463521789765880962939528760888853281920872064838918L), + static_cast(5.28299015654478269617039029170846385138134929147421558771949982217659507918482272439717603L), + static_cast(0.0528999024412510102409256676599360516359062802002483877724963720047531347449011629466149805L), + static_cast(0.000378346710654740685454266569593414561162134092347356968516522170279688139165340746957511115L), + static_cast(0.172194142179211139195966608011235161516824700287310869949928393345257114743230967204370963e-5L), + static_cast(0.374799931707148855771381263542708435935402853962736029347951399323367765509988401336565436e-8L) + }; + static const T denom[24] = { + static_cast(0L), + static_cast(0.112400072777760768e22L), + static_cast(0.414847677933545472e22L), + static_cast(6756146673770930688000.0L), + static_cast(6548684852703068697600.0L), + static_cast(4280722865357147142912.0L), + static_cast(2021687376910682741568.0L), + static_cast(720308216440924653696.0L), + static_cast(199321978221066137360.0L), + static_cast(43714229649594412832.0L), + static_cast(7707401101297361068.0L), + static_cast(1103230881185949736.0L), + static_cast(129006659818331295.0L), + static_cast(12363045847086207.0L), + static_cast(971250460939913.0L), + static_cast(62382416421941.0L), + static_cast(3256091103430.0L), + static_cast(136717357942.0L), + static_cast(4546047198.0L), + static_cast(116896626L), + static_cast(2240315L), + static_cast(30107L), + static_cast(253L), + static_cast(1L) + }; + return boost::math::tools::evaluate_rational(num, denom, z); + } + + + template + static T lanczos_sum_near_1(const T& dz) + { + static const T d[23] = { + static_cast(7.4734083002469026177867421609938203388868806387315406134072298925733950040583068760685908L), + static_cast(-50.4225805042247530267317342133388132970816607563062253708655085754357843064134941138154171L), + static_cast(152.288200621747008570784082624444625293884063492396162110698238568311211546361189979357019L), + static_cast(-271.894959539150384169327513139846971255640842175739337449692360299099322742181325023644769L), + static_cast(319.240102980202312307047586791116902719088581839891008532114107693294261542869734803906793L), + static_cast(-259.493144143048088289689500935518073716201741349569864988870534417890269467336454358361499L), + static_cast(149.747518319689708813209645403067832020714660918583227716408482877303972685262557460145835L), + static_cast(-61.9261301009341333289187201425188698128684426428003249782448828881580630606817104372760037L), + static_cast(18.3077524177286961563937379403377462608113523887554047531153187277072451294845795496072365L), + static_cast(-3.82011322251948043097070160584761236869363471824695092089556195047949392738162970152230254L), + static_cast(0.549382685505691522516705902336780999493262538301283190963770663549981309645795228539620711L), + static_cast(-0.0524814679715180697633723771076668718265358076235229045603747927518423453658004287459638024L), + static_cast(0.00315392664003333528534120626687784812050217700942910879712808180705014754163256855643360698L), + static_cast(-0.000110098373127648510519799564665442121339511198561008748083409549601095293123407080388658329L), + static_cast(0.19809382866681658224945717689377373458866950897791116315219376038432014207446832310901893e-5L), + static_cast(-0.152278977408600291408265615203504153130482270424202400677280558181047344681214058227949755e-7L), + static_cast(0.364344768076106268872239259083188037615571711218395765792787047015406264051536972018235217e-10L), + static_cast(-0.148897510480440424971521542520683536298361220674662555578951242811522959610991621951203526e-13L), + static_cast(0.261199241161582662426512749820666625442516059622425213340053324061794752786482115387573582e-18L), + static_cast(-0.780072664167099103420998436901014795601783313858454665485256897090476089641613851903791529e-24L), + static_cast(0.303465867587106629530056603454807425512962762653755513440561256044986695349304176849392735e-24L), + static_cast(-0.615420597971283870342083342286977366161772327800327789325710571275345878439656918541092056e-25L), + static_cast(0.499641233843540749369110053005439398774706583601830828776209650445427083113181961630763702e-26L), + }; + T result = 0; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(k*dz + k*k); + } + return result; + } + + template + static T lanczos_sum_near_2(const T& dz) + { + static const T d[23] = { + static_cast(61.4165001061101455341808888883960361969557848005400286332291451422461117307237198559485365L), + static_cast(-414.372973678657049667308134761613915623353625332248315105320470271523320700386200587519147L), + static_cast(1251.50505818554680171298972755376376836161706773644771875668053742215217922228357204561873L), + static_cast(-2234.43389421602399514176336175766511311493214354568097811220122848998413358085613880612158L), + static_cast(2623.51647746991904821899989145639147785427273427135380151752779100215839537090464785708684L), + static_cast(-2132.51572435428751962745870184529534443305617818870214348386131243463614597272260797772423L), + static_cast(1230.62572059218405766499842067263311220019173335523810725664442147670956427061920234820189L), + static_cast(-508.90919151163744999377586956023909888833335885805154492270846381061182696305011395981929L), + static_cast(150.453184562246579758706538566480316921938628645961177699894388251635886834047343195475395L), + static_cast(-31.3937061525822497422230490071156186113405446381476081565548185848237169870395131828731397L), + static_cast(4.51482916590287954234936829724231512565732528859217337795452389161322923867318809206313688L), + static_cast(-0.431292919341108177524462194102701868233551186625103849565527515201492276412231365776131952L), + static_cast(0.0259189820815586225636729971503340447445001375909094681698918294680345547092233915092128323L), + static_cast(-0.000904788882557558697594884691337532557729219389814315972435534723829065673966567231504429712L), + static_cast(0.162793589759218213439218473348810982422449144393340433592232065020562974405674317564164312e-4L), + static_cast(-0.125142926178202562426432039899709511761368233479483128438847484617555752948755923647214487e-6L), + static_cast(0.299418680048132583204152682950097239197934281178261879500770485862852229898797687301941982e-9L), + static_cast(-0.122364035267809278675627784883078206654408225276233049012165202996967011873995261617995421e-12L), + static_cast(0.21465364366598631597052073538883430194257709353929022544344097235100199405814005393447785e-17L), + static_cast(-0.641064035802907518396608051803921688237330857546406669209280666066685733941549058513986818e-23L), + static_cast(0.249388374622173329690271566855185869111237201309011956145463506483151054813346819490278951e-23L), + static_cast(-0.505752900177513489906064295001851463338022055787536494321532352380960774349054239257683149e-24L), + static_cast(0.410605371184590959139968810080063542546949719163227555918846829816144878123034347778284006e-25L), + }; + T result = 0; + T z = dz + 2; + for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k) + { + result += (-d[k-1]*dz)/(z + k*z + k*k - 1); + } + return result; + } + + static double g(){ return 20.3209821879863739013671875; } +}; + + +// +// placeholder for no lanczos info available: +// +struct undefined_lanczos : public mpl::int_ { }; + +#if 0 +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +#define BOOST_MATH_FLT_DIGITS ::std::numeric_limits::digits +#define BOOST_MATH_DBL_DIGITS ::std::numeric_limits::digits +#define BOOST_MATH_LDBL_DIGITS ::std::numeric_limits::digits +#else +#define BOOST_MATH_FLT_DIGITS FLT_MANT_DIG +#define BOOST_MATH_DBL_DIGITS DBL_MANT_DIG +#define BOOST_MATH_LDBL_DIGITS LDBL_MANT_DIG +#endif +#endif + +typedef mpl::list< + lanczos6m24, +/* lanczos6, */ + lanczos13m53, +/* lanczos13, */ + lanczos17m64, + lanczos24m113, + lanczos22, + undefined_lanczos> lanczos_list; + +template +struct lanczos +{ + typedef typename mpl::if_< + typename mpl::less_equal< + typename policies::precision::type, + mpl::int_<0> + >::type, + mpl::int_, + typename policies::precision::type + >::type target_precision; + + typedef typename mpl::deref >::type>::type type; +}; + +} // namespace lanczos +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS + + + diff --git a/include/boost/math/special_functions/legendre.hpp b/include/boost/math/special_functions/legendre.hpp new file mode 100644 index 000000000..019df1ed1 --- /dev/null +++ b/include/boost/math/special_functions/legendre.hpp @@ -0,0 +1,189 @@ + +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_LEGENDRE_HPP +#define BOOST_MATH_SPECIAL_LEGENDRE_HPP + +#include +#include +#include + +namespace boost{ +namespace math{ + +// Recurrance relation for legendre P and Q polynomials: +template +inline typename tools::promote_args::type + legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1) +{ + typedef typename tools::promote_args::type result_type; + return ((2 * l + 1) * result_type(x) * result_type(Pl) - l * result_type(Plm1)) / (l + 1); +} + +namespace detail{ + +// Implement Legendre P and Q polynomials via recurrance: +template +T legendre_imp(unsigned l, T x, const Policy& pol, bool second = false) +{ + static const char* function = "boost::math::legrendre_p<%1%>(unsigned, %1%)"; + // Error handling: + if((x < -1) || (x > 1)) + return policies::raise_domain_error( + function, + "The Legendre Polynomial is defined for" + " -1 <= x <= 1, but got x = %1%.", x, pol); + + T p0, p1; + if(second) + { + // A solution of the second kind (Q): + p0 = (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2; + p1 = x * p0 - 1; + } + else + { + // A solution of the first kind (P): + p0 = 1; + p1 = x; + } + if(l == 0) + return p0; + + unsigned n = 1; + + while(n < l) + { + std::swap(p0, p1); + p1 = boost::math::legendre_next(n, x, p0, p1); + ++n; + } + return p1; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + legendre_p(int l, T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + static const char* function = "boost::math::legendre_p<%1%>(unsigned, %1%)"; + if(l < 0) + return policies::checked_narrowing_cast(detail::legendre_imp(-l-1, static_cast(x), pol, false), function); + return policies::checked_narrowing_cast(detail::legendre_imp(l, static_cast(x), pol, false), function); +} + +template +inline typename tools::promote_args::type + legendre_p(int l, T x) +{ + return boost::math::legendre_p(l, x, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + legendre_q(unsigned l, T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::legendre_imp(l, static_cast(x), pol, true), "boost::math::legendre_q<%1%>(unsigned, %1%)"); +} + +template +inline typename tools::promote_args::type + legendre_q(unsigned l, T x) +{ + return boost::math::legendre_q(l, x, policies::policy<>()); +} + +// Recurrence for associated polynomials: +template +inline typename tools::promote_args::type + legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1) +{ + typedef typename tools::promote_args::type result_type; + return ((2 * l + 1) * result_type(x) * result_type(Pl) - (l + m) * result_type(Plm1)) / (l + 1 - m); +} + +namespace detail{ +// Legendre P associated polynomial: +template +T legendre_p_imp(int l, int m, T x, T sin_theta_power, const Policy& pol) +{ + // Error handling: + if((x < -1) || (x > 1)) + return policies::raise_domain_error( + "boost::math::legendre_p<%1%>(int, int, %1%)", + "The associated Legendre Polynomial is defined for" + " -1 <= x <= 1, but got x = %1%.", x, pol); + // Handle negative arguments first: + if(l < 0) + return legendre_p_imp(-l-1, m, x, sin_theta_power, pol); + if(m < 0) + { + int sign = (m&1) ? -1 : 1; + return sign * boost::math::tgamma_ratio(static_cast(l+m+1), static_cast(l+1-m), pol) * legendre_p_imp(l, -m, x, sin_theta_power, pol); + } + // Special cases: + if(m > l) + return 0; + if(m == 0) + return boost::math::legendre_p(l, x, pol); + + T p0 = boost::math::double_factorial(2 * m - 1, pol) * sin_theta_power; + + if(m&1) + p0 *= -1; + if(m == l) + return p0; + + T p1 = x * (2 * m + 1) * p0; + + int n = m + 1; + + while(n < l) + { + std::swap(p0, p1); + p1 = boost::math::legendre_next(n, m, x, p0, p1); + ++n; + } + return p1; +} + +template +inline T legendre_p_imp(int l, int m, T x, const Policy& pol) +{ + BOOST_MATH_STD_USING + // TODO: we really could use that mythical "pow1p" function here: + return legendre_p_imp(l, m, x, pow(1 - x*x, T(abs(m))/2), pol); +} + +} + +template +inline typename tools::promote_args::type + legendre_p(int l, int m, T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::legendre_p_imp(l, m, static_cast(x), pol), "bost::math::legendre_p<%1%>(int, int, %1%)"); +} + +template +inline typename tools::promote_args::type + legendre_p(int l, int m, T x) +{ + return boost::math::legendre_p(l, m, x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_LEGENDRE_HPP + + diff --git a/include/boost/math/special_functions/log1p.hpp b/include/boost/math/special_functions/log1p.hpp index 07db19f54..d5d95eec6 100644 --- a/include/boost/math/special_functions/log1p.hpp +++ b/include/boost/math/special_functions/log1p.hpp @@ -1,4 +1,4 @@ -// (C) Copyright John Maddock 2005. +// (C) Copyright John Maddock 2005-2006. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,7 +9,10 @@ #include #include // platform's ::log1p #include -#include +#include +#include +#include +#include #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS # include @@ -17,77 +20,90 @@ # include #endif -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std{ using ::fabs; using ::log; } -#endif - - namespace boost{ namespace math{ -namespace detail{ - -// -// Functor log1p_series returns the next term in the Taylor series -// pow(-1, k-1)*pow(x, k) / k -// each time that operator() is invoked. -// -template -struct log1p_series +namespace detail { - typedef T result_type; + // Functor log1p_series returns the next term in the Taylor series + // pow(-1, k-1)*pow(x, k) / k + // each time that operator() is invoked. + // + template + struct log1p_series + { + typedef T result_type; - log1p_series(T x) - : k(0), m_mult(-x), m_prod(-1){} + log1p_series(T x) + : k(0), m_mult(-x), m_prod(-1){} - T operator()() - { - m_prod *= m_mult; - return m_prod / ++k; - } + T operator()() + { + m_prod *= m_mult; + return m_prod / ++k; + } - int count()const - { - return k; - } + int count()const + { + return k; + } -private: - int k; - const T m_mult; - T m_prod; - log1p_series(const log1p_series&); - log1p_series& operator=(const log1p_series&); -}; + private: + int k; + const T m_mult; + T m_prod; + log1p_series(const log1p_series&); + log1p_series& operator=(const log1p_series&); + }; -} // namespace +} // namespace detail -// // Algorithm log1p is part of C99, but is not yet provided by many compilers. // // This version uses a Taylor series expansion for 0.5 > x > epsilon, which may -// require up to std::numeric_limits::digits+1 terms to be calculated. It would -// be much more efficient to use the equivalence: -// log(1+x) == (log(1+x) * x) / ((1-x) - 1) -// Unfortunately optimizing compilers make such a mess of this, that it performs -// no better than log(1+x): which is to say not very well at all. +// require up to std::numeric_limits::digits+1 terms to be calculated. +// It would be much more efficient to use the equivalence: +// log(1+x) == (log(1+x) * x) / ((1-x) - 1) +// Unfortunately many optimizing compilers make such a mess of this, that +// it performs no better than log(1+x): which is to say not very well at all. // -template -T log1p(T x) -{ -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(::std::numeric_limits::is_specialized); -#else - BOOST_ASSERT(std::numeric_limits::is_specialized); -#endif - T a = std::fabs(x); - if(a > T(0.5L)) - return std::log(T(1.0) + x); - if(a < std::numeric_limits::epsilon()) +template +typename tools::promote_args::type log1p(T x, const Policy& pol) +{ // The function returns the natural logarithm of 1 + x. + // A domain error occurs if x < -1. TODO should there be a check? + typedef typename tools::promote_args::type result_type; + BOOST_MATH_STD_USING + using std::abs; + + static const char* function = "boost::math::log1p<%1%>(%1%)"; + + if(x < -1) + return policies::raise_domain_error( + function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + function, 0, pol); + + result_type a = abs(result_type(x)); + if(a > result_type(0.5L)) + return log(1 + result_type(x)); + // Note that without numeric_limits specialisation support, + // epsilon just returns zero, and our "optimisation" will always fail: + if(a < tools::epsilon()) return x; - detail::log1p_series s(x); - return detail::kahan_sum_series(s, std::numeric_limits::digits + 2); + detail::log1p_series s(x); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + result_type result = tools::sum_series(s, policies::digits(), max_iter); +#else + result_type zero = 0; + result_type result = tools::sum_series(s, policies::digits(), max_iter, zero); +#endif + policies::check_series_iterations(function, max_iter, pol); + return result; } + #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -// these overloads work around a type deduction bug: +// These overloads work around a type deduction bug: inline float log1p(float z) { return log1p(z); @@ -96,11 +112,13 @@ inline double log1p(double z) { return log1p(z); } +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS inline long double log1p(long double z) { return log1p(z); } #endif +#endif #ifdef log1p # ifndef BOOST_HAS_LOG1P @@ -110,15 +128,150 @@ inline long double log1p(long double z) #endif #ifdef BOOST_HAS_LOG1P -# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) -inline float log1p(float x){ return ::log1pf(x); } -inline long double log1p(long double x){ return ::log1pl(x); } +# if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) \ + || ((defined(linux) || defined(__linux) || defined(__linux__)) && !defined(__SUNPRO_CC)) \ + || (defined(__hpux) && !defined(__hppa)) +template +inline float log1p(float x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + return ::log1pf(x); +} +template +inline long double log1p(long double x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + return ::log1pl(x); +} #else -inline float log1p(float x){ return ::log1p(x); } +template +inline float log1p(float x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + return ::log1p(x); +} #endif -inline double log1p(double x){ return ::log1p(x); } +template +inline double log1p(double x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + return ::log1p(x); +} +#elif defined(_MSC_VER) && (BOOST_MSVC >= 1400) +// +// You should only enable this branch if you are absolutely sure +// that your compilers optimizer won't mess this code up!! +// Currently tested with VC8 and Intel 9.1. +// +template +inline double log1p(double x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + double u = 1+x; + if(u == 1.0) + return x; + else + return log(u)*(x/(u-1.0)); +} +template +inline float log1p(float x, const Policy& pol) +{ + return static_cast(boost::math::log1p(static_cast(x), pol)); +} +template +inline long double log1p(long double x, const Policy& pol) +{ + if(x < -1) + return policies::raise_domain_error( + "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + "log1p<%1%>(%1%)", 0, pol); + long double u = 1+x; + if(u == 1.0) + return x; + else + return log(u)*(x/(u-1.0)); +} #endif -} } // namespaces +template +inline typename tools::promote_args::type log1p(T x) +{ + return boost::math::log1p(x, policies::policy<>()); +} +// +// Compute log(1+x)-x: +// +template +inline typename tools::promote_args::type + log1pmx(T x, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + BOOST_MATH_STD_USING + static const char* function = "boost::math::log1pmx<%1%>(%1%)"; + + if(x < -1) + return policies::raise_domain_error( + function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol); + if(x == -1) + return -policies::raise_overflow_error( + function, 0, pol); + + result_type a = abs(result_type(x)); + if(a > result_type(0.95L)) + return log(1 + result_type(x)) - result_type(x); + // Note that without numeric_limits specialisation support, + // epsilon just returns zero, and our "optimisation" will always fail: + if(a < tools::epsilon()) + return -x * x / 2; + boost::math::detail::log1p_series s(x); + s(); + boost::uintmax_t max_iter = policies::get_max_series_iterations(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + T zero = 0; + T result = boost::math::tools::sum_series(s, policies::digits(), max_iter, zero); +#else + T result = boost::math::tools::sum_series(s, policies::digits(), max_iter); +#endif + policies::check_series_iterations(function, max_iter, pol); + return result; +} + +template +inline T log1pmx(T x) +{ + return log1pmx(x, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_LOG1P_INCLUDED + -#endif // BOOST_MATH_HYPOT_INCLUDED diff --git a/include/boost/math/special_functions/math_fwd.hpp b/include/boost/math/special_functions/math_fwd.hpp new file mode 100644 index 000000000..0414ec066 --- /dev/null +++ b/include/boost/math/special_functions/math_fwd.hpp @@ -0,0 +1,912 @@ +// math_fwd.hpp + +// TODO revise completely for new distribution classes. + +// Copyright Paul A. Bristow 2006. +// Copyright John Maddock 2006. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Omnibus list of forward declarations of math special functions. + +// IT = Integer type. +// RT = Real type (built-in floating-point types, float, double, long double) & User Defined Types +// AT = Integer or Real type + +#ifndef BOOST_MATH_SPECIAL_MATH_FWD_HPP +#define BOOST_MATH_SPECIAL_MATH_FWD_HPP + +#include // for argument promotion. +#include +#include +#include + +#define BOOST_NO_MACRO_EXPAND /**/ + +namespace boost +{ + namespace math + { // Math functions (in roughly alphabetic order). + + // Beta functions. + template + typename tools::promote_args::type + beta(RT1 a, RT2 b); // Beta function (2 arguments). + + template + typename tools::promote_args::type + beta(RT1 a, RT2 b, A x); // Beta function (3 arguments). + + template + typename tools::promote_args::type + beta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Beta function (3 arguments). + + template + typename tools::promote_args::type + betac(RT1 a, RT2 b, RT3 x); + + template + typename tools::promote_args::type + betac(RT1 a, RT2 b, RT3 x, const Policy& pol); + + template + typename tools::promote_args::type + ibeta(RT1 a, RT2 b, RT3 x); // Incomplete beta function. + + template + typename tools::promote_args::type + ibeta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta function. + + template + typename tools::promote_args::type + ibetac(RT1 a, RT2 b, RT3 x); // Incomplete beta complement function. + + template + typename tools::promote_args::type + ibetac(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta complement function. + + template + typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p, T4* py); + + template + typename tools::promote_args::type + ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol); + + template + typename tools::promote_args::type + ibeta_inv(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibeta_inv(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibeta_inva(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibeta_inva(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibeta_invb(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibeta_invb(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function. + + template + typename tools::promote_args::type + ibetac_inv(T1 a, T2 b, T3 q, T4* py); + + template + typename tools::promote_args::type + ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol); + + template + typename tools::promote_args::type + ibetac_inv(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibetac_inva(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibetac_inva(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibetac_invb(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibetac_invb(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function. + + template + typename tools::promote_args::type + ibeta_derivative(RT1 a, RT2 b, RT3 x); // derivative of incomplete beta + + template + typename tools::promote_args::type + ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy& pol); // derivative of incomplete beta + + // erf & erfc error functions. + template // Error function. + typename tools::promote_args::type erf(RT z); + template // Error function. + typename tools::promote_args::type erf(RT z, const Policy&); + + template // Error function complement. + typename tools::promote_args::type erfc(RT z); + template // Error function complement. + typename tools::promote_args::type erfc(RT z, const Policy&); + + template // Error function inverse. + typename tools::promote_args::type erf_inv(RT z); + template // Error function inverse. + typename tools::promote_args::type erf_inv(RT z, const Policy& pol); + + template // Error function complement inverse. + typename tools::promote_args::type erfc_inv(RT z); + template // Error function complement inverse. + typename tools::promote_args::type erfc_inv(RT z, const Policy& pol); + + // Polynomials: + template + typename tools::promote_args::type + legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1); + + template + typename tools::promote_args::type + legendre_p(int l, T x); + + template + typename tools::promote_args::type + legendre_p(int l, T x, const Policy& pol); + + template + typename tools::promote_args::type + legendre_q(unsigned l, T x); + + template + typename tools::promote_args::type + legendre_q(unsigned l, T x, const Policy& pol); + + template + typename tools::promote_args::type + legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1); + + template + typename tools::promote_args::type + legendre_p(int l, int m, T x); + + template + typename tools::promote_args::type + legendre_p(int l, int m, T x, const Policy& pol); + + template + typename tools::promote_args::type + laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1); + + template + typename tools::promote_args::type + laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1); + + template + typename tools::promote_args::type + laguerre(unsigned n, T x); + + template + typename tools::promote_args::type + laguerre(unsigned n, unsigned m, T x, const Policy& pol); + + template + struct laguerre_result + { + typedef typename mpl::if_< + policies::is_policy, + typename tools::promote_args::type, + typename tools::promote_args::type + >::type type; + }; + + template + typename laguerre_result::type + laguerre(unsigned n, T1 m, T2 x); + + template + typename tools::promote_args::type + hermite(unsigned n, T x); + + template + typename tools::promote_args::type + hermite(unsigned n, T x, const Policy& pol); + + template + typename tools::promote_args::type + hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1); + + template + std::complex::type> + spherical_harmonic(unsigned n, int m, T1 theta, T2 phi); + + template + std::complex::type> + spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol); + + template + typename tools::promote_args::type + spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi); + + template + typename tools::promote_args::type + spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol); + + template + typename tools::promote_args::type + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi); + + template + typename tools::promote_args::type + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol); + + // Elliptic integrals: + template + typename tools::promote_args::type + ellint_rf(T1 x, T2 y, T3 z); + + template + typename tools::promote_args::type + ellint_rf(T1 x, T2 y, T3 z, const Policy& pol); + + template + typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z); + + template + typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z, const Policy& pol); + + template + typename tools::promote_args::type + ellint_rc(T1 x, T2 y); + + template + typename tools::promote_args::type + ellint_rc(T1 x, T2 y, const Policy& pol); + + template + typename tools::promote_args::type + ellint_rj(T1 x, T2 y, T3 z, T4 p); + + template + typename tools::promote_args::type + ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol); + + template + typename tools::promote_args::type ellint_2(T k); + + template + typename tools::promote_args::type ellint_2(T1 k, T2 phi); + + template + typename tools::promote_args::type ellint_2(T1 k, T2 phi, const Policy& pol); + + template + typename tools::promote_args::type ellint_1(T k); + + template + typename tools::promote_args::type ellint_1(T1 k, T2 phi); + + template + typename tools::promote_args::type ellint_1(T1 k, T2 phi, const Policy& pol); + + template + typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi); + + template + typename tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol); + + template + typename tools::promote_args::type ellint_3(T1 k, T2 v); + + // Factorial functions. + // Note: not for integral types, at present. + template + struct max_factorial; + template + RT factorial(unsigned int); + template + RT factorial(unsigned int, const Policy& pol); + template + RT unchecked_factorial(unsigned int BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(RT)); + template + RT double_factorial(unsigned i); + template + RT double_factorial(unsigned i, const Policy& pol); + + template + typename tools::promote_args::type falling_factorial(RT x, unsigned n); + + template + typename tools::promote_args::type falling_factorial(RT x, unsigned n, const Policy& pol); + + template + typename tools::promote_args::type rising_factorial(RT x, int n); + + template + typename tools::promote_args::type rising_factorial(RT x, int n, const Policy& pol); + + // Gamma functions. + template + typename tools::promote_args::type tgamma(RT z); + + template + typename tools::promote_args::type tgamma1pm1(RT z); + + template + typename tools::promote_args::type tgamma1pm1(RT z, const Policy& pol); + + template + typename tools::promote_args::type tgamma(RT1 a, RT2 z); + + template + typename tools::promote_args::type tgamma(RT1 a, RT2 z, const Policy& pol); + + template + typename tools::promote_args::type lgamma(RT z, int* sign); + + template + typename tools::promote_args::type lgamma(RT z, int* sign, const Policy& pol); + + template + typename tools::promote_args::type lgamma(RT x); + + template + typename tools::promote_args::type lgamma(RT x, const Policy& pol); + + template + typename tools::promote_args::type tgamma_lower(RT1 a, RT2 z); + + template + typename tools::promote_args::type tgamma_lower(RT1 a, RT2 z, const Policy&); + + template + typename tools::promote_args::type gamma_q(RT1 a, RT2 z); + + template + typename tools::promote_args::type gamma_q(RT1 a, RT2 z, const Policy&); + + template + typename tools::promote_args::type gamma_p(RT1 a, RT2 z); + + template + typename tools::promote_args::type gamma_p(RT1 a, RT2 z, const Policy&); + + template + typename tools::promote_args::type tgamma_delta_ratio(T1 z, T2 delta); + + template + typename tools::promote_args::type tgamma_delta_ratio(T1 z, T2 delta, const Policy&); + + template + typename tools::promote_args::type tgamma_ratio(T1 a, T2 b); + + template + typename tools::promote_args::type tgamma_ratio(T1 a, T2 b, const Policy&); + + template + typename tools::promote_args::type gamma_p_derivative(T1 a, T2 x); + + template + typename tools::promote_args::type gamma_p_derivative(T1 a, T2 x, const Policy&); + + // gamma inverse. + template + typename tools::promote_args::type gamma_p_inv(T1 a, T2 p); + + template + typename tools::promote_args::type gamma_p_inva(T1 a, T2 p, const Policy&); + + template + typename tools::promote_args::type gamma_p_inva(T1 a, T2 p); + + template + typename tools::promote_args::type gamma_p_inv(T1 a, T2 p, const Policy&); + + template + typename tools::promote_args::type gamma_q_inv(T1 a, T2 q); + + template + typename tools::promote_args::type gamma_q_inv(T1 a, T2 q, const Policy&); + + template + typename tools::promote_args::type gamma_q_inva(T1 a, T2 q); + + template + typename tools::promote_args::type gamma_q_inva(T1 a, T2 q, const Policy&); + + // digamma: + template + typename tools::promote_args::type digamma(T x); + + template + typename tools::promote_args::type digamma(T x, const Policy&); + + // Hypotenuse function sqrt(x ^ 2 + y ^ 2). + template + typename tools::promote_args::type + hypot(T1 x, T2 y); + + template + typename tools::promote_args::type + hypot(T1 x, T2 y, const Policy&); + + // cbrt - cube root. + template + typename tools::promote_args::type cbrt(RT z); + + template + typename tools::promote_args::type cbrt(RT z, const Policy&); + + // log1p is log(x + 1) + template + typename tools::promote_args::type log1p(T); + + template + typename tools::promote_args::type log1p(T, const Policy&); + + // log1pmx is log(x + 1) - x + template + typename tools::promote_args::type log1pmx(T); + + template + typename tools::promote_args::type log1pmx(T, const Policy&); + + // Exp (x) minus 1 functions. + template + typename tools::promote_args::type expm1(T); + + template + typename tools::promote_args::type expm1(T, const Policy&); + + // Power - 1 + template + typename tools::promote_args::type + powm1(const T1 a, const T2 z); + + template + typename tools::promote_args::type + powm1(const T1 a, const T2 z, const Policy&); + + // sqrt(1+x) - 1 + template + typename tools::promote_args::type sqrt1pm1(const T& val); + + template + typename tools::promote_args::type sqrt1pm1(const T& val, const Policy&); + + // sinus cardinals: + template + typename tools::promote_args::type sinc_pi(T x); + + template + typename tools::promote_args::type sinc_pi(T x, const Policy&); + + template + typename tools::promote_args::type sinhc_pi(T x); + + template + typename tools::promote_args::type sinhc_pi(T x, const Policy&); + + // inverse hyperbolics: + template + typename tools::promote_args::type asinh(const T x); + + template + typename tools::promote_args::type asinh(const T x, const Policy&); + + template + typename tools::promote_args::type acosh(const T x); + + template + typename tools::promote_args::type acosh(const T x, const Policy&); + + template + typename tools::promote_args::type atanh(const T x); + + template + typename tools::promote_args::type atanh(const T x, const Policy&); + + namespace detail{ + + typedef mpl::int_<0> bessel_no_int_tag; // No integer optimisation possible. + typedef mpl::int_<1> bessel_maybe_int_tag; // Maybe integer optimisation. + typedef mpl::int_<2> bessel_int_tag; // Definite integer optimistaion. + + template + struct bessel_traits + { + typedef typename tools::promote_args< + T1, T2 + >::type result_type; + + typedef typename policies::precision::type precision_type; + + typedef typename mpl::if_< + mpl::or_< + mpl::less_equal >, + mpl::greater > >, + bessel_no_int_tag, + typename mpl::if_< + is_integral, + bessel_int_tag, + bessel_maybe_int_tag + >::type + >::type optimisation_tag; + }; + } // detail + + // Bessel functions: + template + typename detail::bessel_traits::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type cyl_bessel_j(T1 v, T2 x); + + template + typename detail::bessel_traits::result_type sph_bessel(unsigned v, T x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type sph_bessel(unsigned v, T x); + + template + typename detail::bessel_traits::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type cyl_bessel_i(T1 v, T2 x); + + template + typename detail::bessel_traits::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type cyl_bessel_k(T1 v, T2 x); + + template + typename detail::bessel_traits::result_type cyl_neumann(T1 v, T2 x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type cyl_neumann(T1 v, T2 x); + + template + typename detail::bessel_traits::result_type sph_neumann(unsigned v, T x, const Policy& pol); + + template + typename detail::bessel_traits >::result_type sph_neumann(unsigned v, T x); + + template + typename tools::promote_args::type sin_pi(T x, const Policy&); + + template + typename tools::promote_args::type sin_pi(T x); + + template + typename tools::promote_args::type cos_pi(T x, const Policy&); + + template + typename tools::promote_args::type cos_pi(T x); + + template + int fpclassify BOOST_NO_MACRO_EXPAND(T t); + + template + bool isfinite BOOST_NO_MACRO_EXPAND(T z); + + template + bool isinf BOOST_NO_MACRO_EXPAND(T t); + + template + bool isnan BOOST_NO_MACRO_EXPAND(T t); + + template + bool isnormal BOOST_NO_MACRO_EXPAND(T t); + + } // namespace math +} // namespace boost + +#define BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(Policy)\ + template \ + inline typename boost::math::tools::promote_args::type \ + beta(RT1 a, RT2 b) { return ::boost::math::beta(a, b, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + beta(RT1 a, RT2 b, A x){ return ::boost::math::beta(a, b, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + betac(RT1 a, RT2 b, RT3 x) { return ::boost::math::betac(a, b, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta(a, b, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibetac(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibetac(a, b, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta_inv(T1 a, T2 b, T3 p, T4* py){ return ::boost::math::ibeta_inv(a, b, p, py, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta_inv(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inv(a, b, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibetac_inv(T1 a, T2 b, T3 q, T4* py){ return ::boost::math::ibetac_inv(a, b, q, py, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta_inva(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inva(a, b, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibetac_inva(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_inva(a, b, q, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta_invb(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_invb(a, b, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibetac_invb(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_invb(a, b, q, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibetac_inv(RT1 a, RT2 b, RT3 q){ return ::boost::math::ibetac_inv(a, b, q, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ibeta_derivative(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta_derivative(a, b, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type erf(RT z) { return ::boost::math::erf(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type erfc(RT z){ return ::boost::math::erfc(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type erf_inv(RT z) { return ::boost::math::erf_inv(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type erfc_inv(RT z){ return ::boost::math::erfc_inv(z, Policy()); }\ +\ + using boost::math::legendre_next;\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + legendre_p(int l, T x){ return ::boost::math::legendre_p(l, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + legendre_q(unsigned l, T x){ return ::boost::math::legendre_q(l, x, Policy()); }\ +\ + using ::boost::math::legendre_next;\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + legendre_p(int l, int m, T x){ return ::boost::math::legendre_p(l, m, x, Policy()); }\ +\ + using ::boost::math::laguerre_next;\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + laguerre(unsigned n, T x){ return ::boost::math::laguerre(n, x, Policy()); }\ +\ + template \ + inline typename boost::math::laguerre_result::type \ + laguerre(unsigned n, T1 m, T2 x) { return ::boost::math::laguerre(n, m, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + hermite(unsigned n, T x){ return ::boost::math::hermite(n, x, Policy()); }\ +\ + using boost::math::hermite_next;\ +\ + template \ + inline std::complex::type> \ + spherical_harmonic(unsigned n, int m, T1 theta, T2 phi){ return boost::math::spherical_harmonic(n, m, theta, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi){ return ::boost::math::spherical_harmonic_r(n, m, theta, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi){ return boost::math::spherical_harmonic_i(n, m, theta, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ellint_rf(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rf(x, y, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ellint_rd(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rd(x, y, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ellint_rc(T1 x, T2 y){ return ::boost::math::ellint_rc(x, y, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + ellint_rj(T1 x, T2 y, T3 z, T4 p){ return boost::math::ellint_rj(x, y, z, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_2(T k){ return boost::math::ellint_2(k, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_2(T1 k, T2 phi){ return boost::math::ellint_2(k, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_1(T k){ return boost::math::ellint_1(k, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_1(T1 k, T2 phi){ return boost::math::ellint_1(k, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_3(T1 k, T2 v, T3 phi){ return boost::math::ellint_3(k, v, phi, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type ellint_3(T1 k, T2 v){ return boost::math::ellint_3(k, v, Policy()); }\ +\ + using boost::math::max_factorial;\ + template \ + inline RT factorial(unsigned int i) { return boost::math::factorial(i, Policy()); }\ + using boost::math::unchecked_factorial;\ + template \ + inline RT double_factorial(unsigned i){ return boost::math::double_factorial(i, Policy()); }\ + template \ + inline typename boost::math::tools::promote_args::type falling_factorial(RT x, unsigned n){ return boost::math::falling_factorial(x, n, Policy()); }\ + template \ + inline typename boost::math::tools::promote_args::type rising_factorial(RT x, unsigned n){ return boost::math::rising_factorial(x, n, Policy()); }\ + using boost::math::fpclassify;\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma(RT z){ return boost::math::tgamma(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma1pm1(RT z){ return boost::math::tgamma1pm1(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma(RT1 a, RT2 z){ return boost::math::tgamma(a, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type lgamma(RT z, int* sign){ return boost::math::lgamma(z, sign, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type lgamma(RT x){ return boost::math::lgamma(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma_lower(RT1 a, RT2 z){ return boost::math::tgamma_lower(a, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_q(RT1 a, RT2 z){ return boost::math::gamma_q(a, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_p(RT1 a, RT2 z){ return boost::math::gamma_p(a, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma_delta_ratio(T1 z, T2 delta){ return boost::math::tgamma_delta_ratio(z, delta, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type tgamma_ratio(T1 a, T2 b) { return boost::math::tgamma_ratio(a, b, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_p_derivative(T1 a, T2 x){ return boost::math::gamma_p_derivative(a, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_p_inv(T1 a, T2 p){ return boost::math::gamma_p_inv(a, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_p_inva(T1 a, T2 p){ return boost::math::gamma_p_inva(a, p, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_q_inv(T1 a, T2 q){ return boost::math::gamma_q_inv(a, q, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type gamma_q_inva(T1 a, T2 q){ return boost::math::gamma_q_inva(a, q, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type digamma(T x){ return boost::math::digamma(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + hypot(T1 x, T2 y){ return boost::math::hypot(x, y, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type cbrt(RT z){ return boost::math::cbrt(z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type log1p(T x){ return boost::math::log1p(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type log1pmx(T x){ return boost::math::log1pmx(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type expm1(T x){ return boost::math::expm1(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type \ + powm1(const T1 a, const T2 z){ return boost::math::powm1(a, z, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type sqrt1pm1(const T& val){ return boost::math::sqrt1pm1(val, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type sinc_pi(T x){ return boost::math::sinc_pi(x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type sinhc_pi(T x){ return boost::math::sinhc_pi(x, Policy()); }\ +\ + template\ + inline typename boost::math::tools::promote_args::type asinh(const T x){ return boost::math::asinh(x, Policy()); }\ +\ + template\ + inline typename boost::math::tools::promote_args::type acosh(const T x){ return boost::math::acosh(x, Policy()); }\ +\ + template\ + inline typename boost::math::tools::promote_args::type atanh(const T x){ return boost::math::atanh(x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type cyl_bessel_j(T1 v, T2 x)\ + { return boost::math::cyl_bessel_j(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type sph_bessel(unsigned v, T x)\ + { return boost::math::sph_bessel(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type \ + cyl_bessel_i(T1 v, T2 x) { return boost::math::cyl_bessel_i(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type \ + cyl_bessel_k(T1 v, T2 x) { return boost::math::cyl_bessel_k(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type \ + cyl_neumann(T1 v, T2 x){ return boost::math::cyl_neumann(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::detail::bessel_traits::result_type \ + sph_neumann(unsigned v, T x){ return boost::math::sph_neumann(v, x, Policy()); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type sin_pi(T x){ return boost::math::sin_pi(x); }\ +\ + template \ + inline typename boost::math::tools::promote_args::type cos_pi(T x){ return boost::math::cos_pi(x); }\ +\ + using boost::math::fpclassify;\ + using boost::math::isfinite;\ + using boost::math::isinf;\ + using boost::math::isnan;\ + using boost::math::isnormal; + +#endif // BOOST_MATH_SPECIAL_MATH_FWD_HPP diff --git a/include/boost/math/special_functions/powm1.hpp b/include/boost/math/special_functions/powm1.hpp new file mode 100644 index 000000000..dd1467d42 --- /dev/null +++ b/include/boost/math/special_functions/powm1.hpp @@ -0,0 +1,56 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_POWM1 +#define BOOST_MATH_POWM1 + +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +template +inline T powm1_imp(const T a, const T z, const Policy& pol) +{ + BOOST_MATH_STD_USING + + if((fabs(a) < 1) || (fabs(z) < 1)) + { + T p = log(a) * z; + if(fabs(p) < 2) + return boost::math::expm1(p, pol); + // otherwise fall though: + } + return pow(a, z) - 1; +} + +} // detail + +template +inline typename tools::promote_args::type + powm1(const T1 a, const T2 z) +{ + typedef typename tools::promote_args::type result_type; + return detail::powm1_imp(static_cast(a), static_cast(z), policies::policy<>()); +} + +template +inline typename tools::promote_args::type + powm1(const T1 a, const T2 z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + return detail::powm1_imp(static_cast(a), static_cast(z), pol); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_POWM1 + + + + diff --git a/include/boost/math/special_functions/sign.hpp b/include/boost/math/special_functions/sign.hpp new file mode 100644 index 000000000..dd4cb8618 --- /dev/null +++ b/include/boost/math/special_functions/sign.hpp @@ -0,0 +1,38 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_SIGN_HPP +#define BOOST_MATH_TOOLS_SIGN_HPP + +#include +#include + +namespace boost{ namespace math{ + +template +inline int sign BOOST_NO_MACRO_EXPAND(const T& z) +{ + return (z == 0) ? 0 : (z < 0) ? -1 : 1; +} + +template +inline int signbit BOOST_NO_MACRO_EXPAND(const T& z) +{ + return (z < 0) ? 1 : 0; +} + +template +inline T copysign BOOST_NO_MACRO_EXPAND(const T& x, const T& y) +{ + BOOST_MATH_STD_USING + return fabs(x) * boost::math::sign(y); +} + +} // namespace math +} // namespace boost + + +#endif // BOOST_MATH_TOOLS_SIGN_HPP + diff --git a/include/boost/math/special_functions/sin_pi.hpp b/include/boost/math/special_functions/sin_pi.hpp new file mode 100644 index 000000000..c57177d8c --- /dev/null +++ b/include/boost/math/special_functions/sin_pi.hpp @@ -0,0 +1,64 @@ +// Copyright (c) 2007 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SIN_PI_HPP +#define BOOST_MATH_SIN_PI_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace detail{ + +template +T sin_pi_imp(T x) +{ + BOOST_MATH_STD_USING // ADL of std names + // sin of pi*x: + bool invert; + if(x < 0.5) + return sin(constants::pi() * x); + if(x < 1) + { + invert = true; + x = -x; + } + else + invert = false; + + T rem = floor(x); + if(tools::real_cast(rem) & 1) + invert = !invert; + rem = x - rem; + if(rem > 0.5f) + rem = 1 - rem; + if(rem == 0.5f) + return static_cast(invert ? -1 : 1); + + rem = sin(constants::pi() * rem); + return invert ? -rem : rem; +} + +} + +template +inline typename tools::promote_args::type sin_pi(T x, const Policy&) +{ + typedef typename tools::promote_args::type result_type; + return boost::math::detail::sin_pi_imp(x); +} + +template +inline typename tools::promote_args::type sin_pi(T x) +{ + typedef typename tools::promote_args::type result_type; + return boost::math::detail::sin_pi_imp(x); +} + +} // namespace math +} // namespace boost +#endif diff --git a/include/boost/math/special_functions/sinc.hpp b/include/boost/math/special_functions/sinc.hpp index 2816f5166..50788edc8 100644 --- a/include/boost/math/special_functions/sinc.hpp +++ b/include/boost/math/special_functions/sinc.hpp @@ -11,6 +11,10 @@ #define BOOST_SINC_HPP +#include +#include +#include +#include #include #include #include @@ -26,6 +30,8 @@ namespace boost { namespace math { + namespace detail + { #if defined(__GNUC__) && (__GNUC__ < 3) // gcc 2.x ignores function scope using declarations, // put them in the scope of the enclosing namespace instead: @@ -40,9 +46,9 @@ namespace boost // This is the "Sinus Cardinal" of index Pi. template - inline T sinc_pi(const T x) + inline T sinc_pi_imp(const T x) { -#ifdef BOOST_NO_STDC_NAMESPACE +#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC) using ::abs; using ::sin; using ::sqrt; @@ -52,9 +58,8 @@ namespace boost using ::std::sqrt; #endif /* BOOST_NO_STDC_NAMESPACE */ - using ::std::numeric_limits; - - static T const taylor_0_bound = numeric_limits::epsilon(); + // Note: this code is *not* thread safe! + static T const taylor_0_bound = tools::epsilon(); static T const taylor_2_bound = sqrt(taylor_0_bound); static T const taylor_n_bound = sqrt(taylor_2_bound); @@ -85,6 +90,21 @@ namespace boost } } + } // namespace detail + + template + inline typename tools::promote_args::type sinc_pi(T x) + { + typedef typename tools::promote_args::type result_type; + return detail::sinc_pi_imp(static_cast(x)); + } + + template + inline typename tools::promote_args::type sinc_pi(T x, const Policy&) + { + typedef typename tools::promote_args::type result_type; + return detail::sinc_pi_imp(static_cast(x)); + } #ifdef BOOST_NO_TEMPLATE_TEMPLATES #else /* BOOST_NO_TEMPLATE_TEMPLATES */ @@ -105,7 +125,7 @@ namespace boost using ::std::numeric_limits; - static T const taylor_0_bound = numeric_limits::epsilon(); + static T const taylor_0_bound = tools::epsilon(); static T const taylor_2_bound = sqrt(taylor_0_bound); static T const taylor_n_bound = sqrt(taylor_2_bound); @@ -139,6 +159,12 @@ namespace boost return(result); } } + + template class U, class Policy> + inline U sinc_pi(const U x, const Policy&) + { + return sinc_pi(x); + } #endif /* BOOST_NO_TEMPLATE_TEMPLATES */ } } diff --git a/include/boost/math/special_functions/sinhc.hpp b/include/boost/math/special_functions/sinhc.hpp index ed8f4f99c..f5bde4ce9 100644 --- a/include/boost/math/special_functions/sinhc.hpp +++ b/include/boost/math/special_functions/sinhc.hpp @@ -11,6 +11,9 @@ #define BOOST_SINHC_HPP +#include +#include +#include #include #include #include @@ -26,6 +29,8 @@ namespace boost { namespace math { + namespace detail + { #if defined(__GNUC__) && (__GNUC__ < 3) // gcc 2.x ignores function scope using declarations, // put them in the scope of the enclosing namespace instead: @@ -40,9 +45,9 @@ namespace boost // This is the "Hyperbolic Sinus Cardinal" of index Pi. template - inline T sinhc_pi(const T x) + inline T sinhc_pi_imp(const T x) { -#ifdef BOOST_NO_STDC_NAMESPACE +#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC) using ::abs; using ::sinh; using ::sqrt; @@ -52,9 +57,7 @@ namespace boost using ::std::sqrt; #endif /* BOOST_NO_STDC_NAMESPACE */ - using ::std::numeric_limits; - - static T const taylor_0_bound = numeric_limits::epsilon(); + static T const taylor_0_bound = tools::epsilon(); static T const taylor_2_bound = sqrt(taylor_0_bound); static T const taylor_n_bound = sqrt(taylor_2_bound); @@ -85,6 +88,20 @@ namespace boost } } + } // namespace detail + + template + inline typename tools::promote_args::type sinhc_pi(T x) + { + typedef typename tools::promote_args::type result_type; + return detail::sinhc_pi_imp(static_cast(x)); + } + + template + inline typename tools::promote_args::type sinhc_pi(T x, const Policy&) + { + return boost::math::sinhc_pi(x); + } #ifdef BOOST_NO_TEMPLATE_TEMPLATES #else /* BOOST_NO_TEMPLATE_TEMPLATES */ @@ -105,7 +122,7 @@ namespace boost using ::std::numeric_limits; - static T const taylor_0_bound = numeric_limits::epsilon(); + static T const taylor_0_bound = tools::epsilon(); static T const taylor_2_bound = sqrt(taylor_0_bound); static T const taylor_n_bound = sqrt(taylor_2_bound); diff --git a/include/boost/math/special_functions/spherical_harmonic.hpp b/include/boost/math/special_functions/spherical_harmonic.hpp new file mode 100644 index 000000000..fae32ad97 --- /dev/null +++ b/include/boost/math/special_functions/spherical_harmonic.hpp @@ -0,0 +1,199 @@ + +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP +#define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP + +#include +#include +#include + +namespace boost{ +namespace math{ + +namespace detail{ + +// +// Calculates the prefix term that's common to the real +// and imaginary parts. Does *not* fix up the sign of the result +// though. +// +template +inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol) +{ + BOOST_MATH_STD_USING + + if(m > n) + return 0; + + T sin_theta = sin(theta); + T x = cos(theta); + + T leg = detail::legendre_p_imp(n, m, x, pow(fabs(sin_theta), T(m)), pol); + + T prefix = boost::math::tgamma_delta_ratio(static_cast(n - m + 1), static_cast(2 * m), pol); + prefix *= (2 * n + 1) / (4 * constants::pi()); + prefix = sqrt(prefix); + return prefix * leg; +} +// +// Real Part: +// +template +T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std functions + + bool sign = false; + if(m < 0) + { + // Reflect and adjust sign if m < 0: + sign = m&1; + m = abs(m); + } + if(m&1) + { + // Check phase if theta is outside [0, PI]: + T mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi()); + if(mod < 0) + mod += 2 * constants::pi(); + if(mod > constants::pi()) + sign = !sign; + } + // Get the value and adjust sign as required: + T prefix = spherical_harmonic_prefix(n, m, theta, pol); + prefix *= cos(m * phi); + return sign ? -prefix : prefix; +} + +template +T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol) +{ + BOOST_MATH_STD_USING // ADL of std functions + + bool sign = false; + if(m < 0) + { + // Reflect and adjust sign if m < 0: + sign = !(m&1); + m = abs(m); + } + if(m&1) + { + // Check phase if theta is outside [0, PI]: + T mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi()); + if(mod < 0) + mod += 2 * constants::pi(); + if(mod > constants::pi()) + sign = !sign; + } + // Get the value and adjust sign as required: + T prefix = spherical_harmonic_prefix(n, m, theta, pol); + prefix *= sin(m * phi); + return sign ? -prefix : prefix; +} + +template +std::complex spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol) +{ + BOOST_MATH_STD_USING + // + // Sort out the signs: + // + bool r_sign = false; + bool i_sign = false; + if(m < 0) + { + // Reflect and adjust sign if m < 0: + r_sign = m&1; + i_sign = !(m&1); + m = abs(m); + } + if(m&1) + { + // Check phase if theta is outside [0, PI]: + U mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi()); + if(mod < 0) + mod += 2 * constants::pi(); + if(mod > constants::pi()) + { + r_sign = !r_sign; + i_sign = !i_sign; + } + } + // + // Calculate the value: + // + U prefix = spherical_harmonic_prefix(n, m, theta, pol); + U r = prefix * cos(m * phi); + U i = prefix * sin(m * phi); + // + // Add in the signs: + // + if(r_sign) + r = -r; + if(i_sign) + i = -i; + static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)"; + return std::complex(policies::checked_narrowing_cast(r, function), policies::checked_narrowing_cast(i, function)); +} + +} // namespace detail + +template +inline std::complex::type> + spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return detail::spherical_harmonic(n, m, static_cast(theta), static_cast(phi), pol); +} + +template +inline std::complex::type> + spherical_harmonic(unsigned n, int m, T1 theta, T2 phi) +{ + return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::spherical_harmonic_r(n, m, static_cast(theta), static_cast(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)"); +} + +template +inline typename tools::promote_args::type + spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi) +{ + return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>()); +} + +template +inline typename tools::promote_args::type + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast(detail::spherical_harmonic_i(n, m, static_cast(theta), static_cast(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)"); +} + +template +inline typename tools::promote_args::type + spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi) +{ + return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP + + diff --git a/include/boost/math/special_functions/sqrt1pm1.hpp b/include/boost/math/special_functions/sqrt1pm1.hpp new file mode 100644 index 000000000..ea4929e1f --- /dev/null +++ b/include/boost/math/special_functions/sqrt1pm1.hpp @@ -0,0 +1,43 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SQRT1PM1 +#define BOOST_MATH_SQRT1PM1 + +#include +#include +#include + +// +// This algorithm computes sqrt(1+x)-1 for small x: +// + +namespace boost{ namespace math{ + +template +inline typename tools::promote_args::type sqrt1pm1(const T& val, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + BOOST_MATH_STD_USING + + if(fabs(result_type(val)) > 0.75) + return sqrt(1 + result_type(val)) - 1; + return boost::math::expm1(boost::math::log1p(val, pol) / 2, pol); +} + +template +inline typename tools::promote_args::type sqrt1pm1(const T& val) +{ + return sqrt1pm1(val, policies::policy<>()); +} + +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_SQRT1PM1 + + + + diff --git a/include/boost/math/tools/config.hpp b/include/boost/math/tools/config.hpp new file mode 100644 index 000000000..aaab87aba --- /dev/null +++ b/include/boost/math/tools/config.hpp @@ -0,0 +1,246 @@ +// Copyright (c) 2006-7 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_CONFIG_HPP +#define BOOST_MATH_TOOLS_CONFIG_HPP + +#include // for boost::uintmax_t +#include +#include +#include // for min and max +#include +#include +#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) +# include +#endif + +#include + +#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__hppa) +# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#endif +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +// +// Borland post 5.8.2 uses Dinkumware's std C lib which +// doesn't have true long double precision. Earlier +// versions are problematic too: +// +# define BOOST_MATH_NO_REAL_CONCEPT_TESTS +# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +# define BOOST_MATH_CONTROL_FP _control87(MCW_EM,MCW_EM) +# include +#endif +#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106)) +// +// Darwin's rather strange "double double" is rather hard to +// support, it should be possible given enough effort though... +// +# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#endif +#if defined(unix) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER <= 1000) +// +// Intel compiler prior to version 10 has sporadic problems +// calling the long double overloads of the std lib math functions: +// calling ::powl is OK, but std::pow(long double, long double) +// may segfault depending upon the value of the arguments passed +// and the specific Linux distribution. +// +// We'll be conservative and disable long double support for this compiler. +// +// Comment out this #define and try building the tests to determine whether +// your Intel compiler version has this issue or not. +// +# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#endif + +#ifdef __IBMCPP__ +# define BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS +#endif + +#if defined(BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS) || BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) + +# include "boost/type.hpp" +# include "boost/non_type.hpp" + +# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t) boost::type* = 0 +# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t) boost::type* +# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v) boost::non_type* = 0 +# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) boost::non_type* + +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(t) \ + , BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(t) \ + , BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(t, v) \ + , BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) \ + , BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) + +#else + +// no workaround needed: expand to nothing + +# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t) +# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t) +# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v) +# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) + +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(t) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(t) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(t, v) +# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) + + +#endif // defined BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS + +#if BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) || defined(__hppa) +// Sun's compiler emits a hard error if a constant underflows, +// as does aCC on PA-RISC: +# define BOOST_MATH_SMALL_CONSTANT(x) 0 +#else +# define BOOST_MATH_SMALL_CONSTANT(x) x +#endif + + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) +// +// Define if constants too large for a float cause "bad" +// values to be stored in the data, rather than infinity +// or a suitably large value. +// +# define BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS +#endif +// +// Tune performance options for specific compilers: +// +#ifdef BOOST_MSVC +# define BOOST_MATH_POLY_METHOD 3 +#elif defined(BOOST_INTEL) +# define BOOST_MATH_POLY_METHOD 2 +# define BOOST_MATH_RATIONAL_METHOD 2 +#elif defined(__GNUC__) +# define BOOST_MATH_POLY_METHOD 3 +# define BOOST_MATH_RATIONAL_METHOD 3 +# define BOOST_MATH_INT_TABLE_TYPE(RT, IT) RT +#endif + +// +// The maximum order of polynomial that will be evaluated +// via an unrolled specialisation: +// +#ifndef BOOST_MATH_MAX_POLY_ORDER +# define BOOST_MATH_MAX_POLY_ORDER 17 +#endif +// +// Set the method used to evaluate polynomials and rationals: +// +#ifndef BOOST_MATH_POLY_METHOD +# define BOOST_MATH_POLY_METHOD 1 +#endif +#ifndef BOOST_MATH_RATIONAL_METHOD +# define BOOST_MATH_RATIONAL_METHOD 0 +#endif +// +// decide whether to store constants as integers or reals: +// +#ifndef BOOST_MATH_INT_TABLE_TYPE +# define BOOST_MATH_INT_TABLE_TYPE(RT, IT) IT +#endif +// +// Helper macro for controlling the FP behaviour: +// +#ifndef BOOST_MATH_CONTROL_FP +# define BOOST_MATH_CONTROL_FP +#endif +// +// Helper macro for using statements: +// +#define BOOST_MATH_STD_USING \ + using std::abs;\ + using std::acos;\ + using std::cos;\ + using std::fmod;\ + using std::modf;\ + using std::tan;\ + using std::asin;\ + using std::cosh;\ + using std::frexp;\ + using std::pow;\ + using std::tanh;\ + using std::atan;\ + using std::exp;\ + using std::ldexp;\ + using std::sin;\ + using std::atan2;\ + using std::fabs;\ + using std::log;\ + using std::sinh;\ + using std::ceil;\ + using std::floor;\ + using std::log10;\ + using std::sqrt; + + +namespace boost{ namespace math{ +namespace tools +{ + +template +inline T max BOOST_PREVENT_MACRO_SUBSTITUTION(T a, T b, T c) +{ + return (std::max)((std::max)(a, b), c); +} + +template +inline T max BOOST_PREVENT_MACRO_SUBSTITUTION(T a, T b, T c, T d) +{ + return (std::max)((std::max)(a, b), (std::max)(c, d)); +} +} // namespace tools +}} // namespace boost namespace math + +#ifdef __linux__ + + #include + + namespace boost{ namespace math{ + namespace detail + { + struct fpu_guard + { + fpu_guard() + { + fegetexceptflag(&m_flags, FE_ALL_EXCEPT); + feclearexcept(FE_ALL_EXCEPT); + } + ~fpu_guard() + { + fesetexceptflag(&m_flags, FE_ALL_EXCEPT); + } + private: + fexcept_t m_flags; + }; + + } // namespace detail + }} // namespaces + + #define BOOST_FPU_EXCEPTION_GUARD boost::math::detail::fpu_guard local_guard_object; +#else // All other platforms. + #define BOOST_FPU_EXCEPTION_GUARD +#endif + +#ifdef BOOST_MATH_INSTRUMENT +#define BOOST_MATH_INSTRUMENT_CODE(x) \ + std::cout << std::setprecision(35) << __FILE__ << ":" << __LINE__ << " " << x << std::endl; +#define BOOST_MATH_INSTRUMENT_VARIABLE(name) BOOST_MATH_INSTRUMENT_CODE(BOOST_STRINGIZE(name) << " = " << name) +#else +#define BOOST_MATH_INSTRUMENT_CODE(x) +#define BOOST_MATH_INSTRUMENT_VARIABLE(name) +#endif + +#endif // BOOST_MATH_TOOLS_CONFIG_HPP + + + diff --git a/include/boost/math/tools/detail/polynomial_horner1_10.hpp b/include/boost/math/tools/detail/polynomial_horner1_10.hpp new file mode 100644 index 000000000..ffc3a6804 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_10.hpp @@ -0,0 +1,84 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_10_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_11.hpp b/include/boost/math/tools/detail/polynomial_horner1_11.hpp new file mode 100644 index 000000000..8e2232c53 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_11.hpp @@ -0,0 +1,90 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_11_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_12.hpp b/include/boost/math/tools/detail/polynomial_horner1_12.hpp new file mode 100644 index 000000000..07d2947c9 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_12.hpp @@ -0,0 +1,96 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_12_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_13.hpp b/include/boost/math/tools/detail/polynomial_horner1_13.hpp new file mode 100644 index 000000000..d826b5150 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_13.hpp @@ -0,0 +1,102 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_13_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_14.hpp b/include/boost/math/tools/detail/polynomial_horner1_14.hpp new file mode 100644 index 000000000..02b23ada5 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_14.hpp @@ -0,0 +1,108 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_14_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_15.hpp b/include/boost/math/tools/detail/polynomial_horner1_15.hpp new file mode 100644 index 000000000..72cbbd298 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_15.hpp @@ -0,0 +1,114 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_15_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_16.hpp b/include/boost/math/tools/detail/polynomial_horner1_16.hpp new file mode 100644 index 000000000..39202e001 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_16.hpp @@ -0,0 +1,120 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_16_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + return static_cast(((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_17.hpp b/include/boost/math/tools/detail/polynomial_horner1_17.hpp new file mode 100644 index 000000000..a777ab76b --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_17.hpp @@ -0,0 +1,126 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_17_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + return static_cast(((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + return static_cast((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_18.hpp b/include/boost/math/tools/detail/polynomial_horner1_18.hpp new file mode 100644 index 000000000..57e171c6b --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_18.hpp @@ -0,0 +1,132 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_18_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + return static_cast(((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + return static_cast((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + return static_cast(((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_19.hpp b/include/boost/math/tools/detail/polynomial_horner1_19.hpp new file mode 100644 index 000000000..f2e893d65 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_19.hpp @@ -0,0 +1,138 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_19_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + return static_cast(((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + return static_cast((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + return static_cast(((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + return static_cast((((((((((((((((((a[18] * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_2.hpp b/include/boost/math/tools/detail/polynomial_horner1_2.hpp new file mode 100644 index 000000000..cf2af8ec2 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_2.hpp @@ -0,0 +1,36 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_2_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_20.hpp b/include/boost/math/tools/detail/polynomial_horner1_20.hpp new file mode 100644 index 000000000..6cd2fa2ca --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_20.hpp @@ -0,0 +1,144 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_20_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + return static_cast(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + return static_cast((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + return static_cast(((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + return static_cast((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + return static_cast(((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + return static_cast((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + return static_cast(((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + return static_cast((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + return static_cast(((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + return static_cast((((((((((((((((((a[18] * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<20>*) +{ + return static_cast(((((((((((((((((((a[19] * x + a[18]) * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_3.hpp b/include/boost/math/tools/detail/polynomial_horner1_3.hpp new file mode 100644 index 000000000..34283d1cf --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_3.hpp @@ -0,0 +1,42 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_3_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_4.hpp b/include/boost/math/tools/detail/polynomial_horner1_4.hpp new file mode 100644 index 000000000..7a06708e0 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_4.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_4_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_5.hpp b/include/boost/math/tools/detail/polynomial_horner1_5.hpp new file mode 100644 index 000000000..135e155ec --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_5.hpp @@ -0,0 +1,54 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_5_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_6.hpp b/include/boost/math/tools/detail/polynomial_horner1_6.hpp new file mode 100644 index 000000000..af993517c --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_6.hpp @@ -0,0 +1,60 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_6_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_7.hpp b/include/boost/math/tools/detail/polynomial_horner1_7.hpp new file mode 100644 index 000000000..9205f2efa --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_7.hpp @@ -0,0 +1,66 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_7_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_8.hpp b/include/boost/math/tools/detail/polynomial_horner1_8.hpp new file mode 100644 index 000000000..70afa9008 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_8.hpp @@ -0,0 +1,72 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_8_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner1_9.hpp b/include/boost/math/tools/detail/polynomial_horner1_9.hpp new file mode 100644 index 000000000..b823f24b5 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner1_9.hpp @@ -0,0 +1,78 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_9_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + return static_cast((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + return static_cast(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + return static_cast((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + return static_cast(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + return static_cast((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_10.hpp b/include/boost/math/tools/detail/polynomial_horner2_10.hpp new file mode 100644 index 000000000..0474d7e3e --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_10.hpp @@ -0,0 +1,90 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_10_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_11.hpp b/include/boost/math/tools/detail/polynomial_horner2_11.hpp new file mode 100644 index 000000000..6fd1ea99e --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_11.hpp @@ -0,0 +1,97 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_11_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_12.hpp b/include/boost/math/tools/detail/polynomial_horner2_12.hpp new file mode 100644 index 000000000..c6615c7ac --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_12.hpp @@ -0,0 +1,104 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_12_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_13.hpp b/include/boost/math/tools/detail/polynomial_horner2_13.hpp new file mode 100644 index 000000000..02f4136b7 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_13.hpp @@ -0,0 +1,111 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_13_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_14.hpp b/include/boost/math/tools/detail/polynomial_horner2_14.hpp new file mode 100644 index 000000000..34d27cc9f --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_14.hpp @@ -0,0 +1,118 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_14_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_15.hpp b/include/boost/math/tools/detail/polynomial_horner2_15.hpp new file mode 100644 index 000000000..a1615243f --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_15.hpp @@ -0,0 +1,125 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_15_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_16.hpp b/include/boost/math/tools/detail/polynomial_horner2_16.hpp new file mode 100644 index 000000000..43a2679bf --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_16.hpp @@ -0,0 +1,132 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_16_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + return static_cast((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_17.hpp b/include/boost/math/tools/detail/polynomial_horner2_17.hpp new file mode 100644 index 000000000..83dd92129 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_17.hpp @@ -0,0 +1,139 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_17_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + return static_cast((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + return static_cast((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_18.hpp b/include/boost/math/tools/detail/polynomial_horner2_18.hpp new file mode 100644 index 000000000..8a13a049e --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_18.hpp @@ -0,0 +1,146 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_18_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + return static_cast((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + return static_cast((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + return static_cast(((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_19.hpp b/include/boost/math/tools/detail/polynomial_horner2_19.hpp new file mode 100644 index 000000000..38e522634 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_19.hpp @@ -0,0 +1,153 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_19_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + return static_cast((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + return static_cast((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + return static_cast(((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + V x2 = x * x; + return static_cast(((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_2.hpp b/include/boost/math/tools/detail/polynomial_horner2_2.hpp new file mode 100644 index 000000000..5421d828c --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_2.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_2_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_20.hpp b/include/boost/math/tools/detail/polynomial_horner2_20.hpp new file mode 100644 index 000000000..dd422705c --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_20.hpp @@ -0,0 +1,160 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_20_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + return static_cast(((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + return static_cast(((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + return static_cast((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + return static_cast((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + return static_cast(((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + return static_cast(((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + return static_cast((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + return static_cast((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + return static_cast(((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + V x2 = x * x; + return static_cast(((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<20>*) +{ + V x2 = x * x; + return static_cast((((((((((a[19] * x2 + a[17]) * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_3.hpp b/include/boost/math/tools/detail/polynomial_horner2_3.hpp new file mode 100644 index 000000000..cd568ab79 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_3.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_3_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_4.hpp b/include/boost/math/tools/detail/polynomial_horner2_4.hpp new file mode 100644 index 000000000..a99a695c7 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_4.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_4_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_5.hpp b/include/boost/math/tools/detail/polynomial_horner2_5.hpp new file mode 100644 index 000000000..950568f9d --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_5.hpp @@ -0,0 +1,55 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_5_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_6.hpp b/include/boost/math/tools/detail/polynomial_horner2_6.hpp new file mode 100644 index 000000000..b1035f503 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_6.hpp @@ -0,0 +1,62 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_6_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_7.hpp b/include/boost/math/tools/detail/polynomial_horner2_7.hpp new file mode 100644 index 000000000..0b167564d --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_7.hpp @@ -0,0 +1,69 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_7_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_8.hpp b/include/boost/math/tools/detail/polynomial_horner2_8.hpp new file mode 100644 index 000000000..ba92c21e2 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_8.hpp @@ -0,0 +1,76 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_8_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner2_9.hpp b/include/boost/math/tools/detail/polynomial_horner2_9.hpp new file mode 100644 index 000000000..cc4afb38d --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner2_9.hpp @@ -0,0 +1,83 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_9_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + return static_cast((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + return static_cast(((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + return static_cast(((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + return static_cast((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + return static_cast((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_10.hpp b/include/boost/math/tools/detail/polynomial_horner3_10.hpp new file mode 100644 index 000000000..14b1b66f3 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_10.hpp @@ -0,0 +1,156 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_10_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_11.hpp b/include/boost/math/tools/detail/polynomial_horner3_11.hpp new file mode 100644 index 000000000..690906938 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_11.hpp @@ -0,0 +1,181 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_11_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_12.hpp b/include/boost/math/tools/detail/polynomial_horner3_12.hpp new file mode 100644 index 000000000..d17d3c586 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_12.hpp @@ -0,0 +1,208 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_12_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_13.hpp b/include/boost/math/tools/detail/polynomial_horner3_13.hpp new file mode 100644 index 000000000..aff043bd1 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_13.hpp @@ -0,0 +1,237 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_13_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_14.hpp b/include/boost/math/tools/detail/polynomial_horner3_14.hpp new file mode 100644 index 000000000..5ff2a51de --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_14.hpp @@ -0,0 +1,268 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_14_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_15.hpp b/include/boost/math/tools/detail/polynomial_horner3_15.hpp new file mode 100644 index 000000000..896545617 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_15.hpp @@ -0,0 +1,301 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_15_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_16.hpp b/include/boost/math/tools/detail/polynomial_horner3_16.hpp new file mode 100644 index 000000000..5bfddc59a --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_16.hpp @@ -0,0 +1,336 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_16_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_17.hpp b/include/boost/math/tools/detail/polynomial_horner3_17.hpp new file mode 100644 index 000000000..d6679b392 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_17.hpp @@ -0,0 +1,373 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_17_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[16] * x2 + a[14]); + t[1] = static_cast(a[15] * x2 + a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_18.hpp b/include/boost/math/tools/detail/polynomial_horner3_18.hpp new file mode 100644 index 000000000..df016a173 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_18.hpp @@ -0,0 +1,412 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_18_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[16] * x2 + a[14]); + t[1] = static_cast(a[15] * x2 + a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_19.hpp b/include/boost/math/tools/detail/polynomial_horner3_19.hpp new file mode 100644 index 000000000..10adbe556 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_19.hpp @@ -0,0 +1,453 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_19_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[16] * x2 + a[14]); + t[1] = static_cast(a[15] * x2 + a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[18] * x2 + a[16]); + t[1] = static_cast(a[17] * x2 + a[15]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_2.hpp b/include/boost/math/tools/detail/polynomial_horner3_2.hpp new file mode 100644 index 000000000..b32501f0a --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_2.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_2_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_20.hpp b/include/boost/math/tools/detail/polynomial_horner3_20.hpp new file mode 100644 index 000000000..68bd0bead --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_20.hpp @@ -0,0 +1,496 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_20_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[10] * x2 + a[8]); + t[1] = static_cast(a[9] * x2 + a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<12>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<13>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[12] * x2 + a[10]); + t[1] = static_cast(a[11] * x2 + a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<14>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<15>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[14] * x2 + a[12]); + t[1] = static_cast(a[13] * x2 + a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<16>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<17>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[16] * x2 + a[14]); + t[1] = static_cast(a[15] * x2 + a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<18>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<19>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[18] * x2 + a[16]); + t[1] = static_cast(a[17] * x2 + a[15]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[13]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<20>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[19] * x2 + a[17]; + t[1] = a[18] * x2 + a[16]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[15]); + t[1] += static_cast(a[14]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_3.hpp b/include/boost/math/tools/detail/polynomial_horner3_3.hpp new file mode 100644 index 000000000..8296740a5 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_3.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_3_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_4.hpp b/include/boost/math/tools/detail/polynomial_horner3_4.hpp new file mode 100644 index 000000000..e6ba3179b --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_4.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_4_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_5.hpp b/include/boost/math/tools/detail/polynomial_horner3_5.hpp new file mode 100644 index 000000000..d4e94b90d --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_5.hpp @@ -0,0 +1,61 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_5_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_6.hpp b/include/boost/math/tools/detail/polynomial_horner3_6.hpp new file mode 100644 index 000000000..143defc63 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_6.hpp @@ -0,0 +1,76 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_6_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_7.hpp b/include/boost/math/tools/detail/polynomial_horner3_7.hpp new file mode 100644 index 000000000..016895076 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_7.hpp @@ -0,0 +1,93 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_7_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_8.hpp b/include/boost/math/tools/detail/polynomial_horner3_8.hpp new file mode 100644 index 000000000..9a373446e --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_8.hpp @@ -0,0 +1,112 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_8_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/polynomial_horner3_9.hpp b/include/boost/math/tools/detail/polynomial_horner3_9.hpp new file mode 100644 index 000000000..d0f9dd310 --- /dev/null +++ b/include/boost/math/tools/detail/polynomial_horner3_9.hpp @@ -0,0 +1,133 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Unrolled polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_EVAL_9_HPP +#define BOOST_MATH_TOOLS_POLY_EVAL_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*) +{ + return static_cast(a[1] * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*) +{ + return static_cast((a[2] * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*) +{ + return static_cast(((a[3] * x + a[2]) * x + a[1]) * x + a[0]); +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[4] * x2 + a[2]); + t[1] = static_cast(a[3] * x2 + a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[6] * x2 + a[4]); + t[1] = static_cast(a[5] * x2 + a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*) +{ + V x2 = x * x; + V t[2]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[0] *= x; + return t[0] + t[1]; +} + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*) +{ + V x2 = x * x; + V t[2]; + t[0] = static_cast(a[8] * x2 + a[6]); + t[1] = static_cast(a[7] * x2 + a[5]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[0] *= x2; + t[1] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[0] *= x2; + t[0] += static_cast(a[0]); + t[1] *= x; + return t[0] + t[1]; +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_10.hpp b/include/boost/math/tools/detail/rational_horner1_10.hpp new file mode 100644 index 000000000..919ba6d09 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_10.hpp @@ -0,0 +1,138 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_10_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_11.hpp b/include/boost/math/tools/detail/rational_horner1_11.hpp new file mode 100644 index 000000000..e17bfbc72 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_11.hpp @@ -0,0 +1,150 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_11_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_12.hpp b/include/boost/math/tools/detail/rational_horner1_12.hpp new file mode 100644 index 000000000..67b430a99 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_12.hpp @@ -0,0 +1,162 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_12_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_13.hpp b/include/boost/math/tools/detail/rational_horner1_13.hpp new file mode 100644 index 000000000..33ae67523 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_13.hpp @@ -0,0 +1,174 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_13_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_14.hpp b/include/boost/math/tools/detail/rational_horner1_14.hpp new file mode 100644 index 000000000..0c5f1884c --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_14.hpp @@ -0,0 +1,186 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_14_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_15.hpp b/include/boost/math/tools/detail/rational_horner1_15.hpp new file mode 100644 index 000000000..848190761 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_15.hpp @@ -0,0 +1,198 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_15_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_16.hpp b/include/boost/math/tools/detail/rational_horner1_16.hpp new file mode 100644 index 000000000..e0661f8b3 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_16.hpp @@ -0,0 +1,210 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_16_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + return static_cast((((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((b[15] * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) / (((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_17.hpp b/include/boost/math/tools/detail/rational_horner1_17.hpp new file mode 100644 index 000000000..f123da4c9 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_17.hpp @@ -0,0 +1,222 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_17_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + return static_cast((((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((b[15] * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) / (((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((b[16] * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) / ((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_18.hpp b/include/boost/math/tools/detail/rational_horner1_18.hpp new file mode 100644 index 000000000..718ace87f --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_18.hpp @@ -0,0 +1,234 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_18_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + return static_cast((((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((b[15] * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) / (((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((b[16] * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) / ((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + return static_cast((((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((((b[17] * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) / (((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_19.hpp b/include/boost/math/tools/detail/rational_horner1_19.hpp new file mode 100644 index 000000000..c849ba8c0 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_19.hpp @@ -0,0 +1,246 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_19_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + return static_cast((((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((b[15] * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) / (((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((b[16] * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) / ((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + return static_cast((((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((((b[17] * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) / (((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((((a[18] * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((((b[18] * x + b[17]) * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) * z + a[18]) / ((((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17]) * z + b[18])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_2.hpp b/include/boost/math/tools/detail/rational_horner1_2.hpp new file mode 100644 index 000000000..87e41ab3f --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_2.hpp @@ -0,0 +1,42 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_2_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_20.hpp b/include/boost/math/tools/detail/rational_horner1_20.hpp new file mode 100644 index 000000000..e05eaaa89 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_20.hpp @@ -0,0 +1,258 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_20_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + return static_cast((((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((b[9] * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) / (((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + return static_cast(((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((b[10] * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) / ((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + return static_cast((((((((((((a[11] * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((b[11] * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) / (((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + return static_cast(((((((((((((a[12] * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((b[12] * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) / ((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + return static_cast((((((((((((((a[13] * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((b[13] * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) / (((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + return static_cast(((((((((((((((a[14] * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((b[14] * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) / ((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + return static_cast((((((((((((((((a[15] * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((b[15] * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) / (((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((a[16] * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((b[16] * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) / ((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + return static_cast((((((((((((((((((a[17] * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((((b[17] * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) / (((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + return static_cast(((((((((((((((((((a[18] * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((((((((((((b[18] * x + b[17]) * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) * z + a[18]) / ((((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17]) * z + b[18])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<20>*) +{ + if(x <= 1) + return static_cast((((((((((((((((((((a[19] * x + a[18]) * x + a[17]) * x + a[16]) * x + a[15]) * x + a[14]) * x + a[13]) * x + a[12]) * x + a[11]) * x + a[10]) * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((((((((((((((b[19] * x + b[18]) * x + b[17]) * x + b[16]) * x + b[15]) * x + b[14]) * x + b[13]) * x + b[12]) * x + b[11]) * x + b[10]) * x + b[9]) * x + b[8]) * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((((((((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) * z + a[9]) * z + a[10]) * z + a[11]) * z + a[12]) * z + a[13]) * z + a[14]) * z + a[15]) * z + a[16]) * z + a[17]) * z + a[18]) * z + a[19]) / (((((((((((((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8]) * z + b[9]) * z + b[10]) * z + b[11]) * z + b[12]) * z + b[13]) * z + b[14]) * z + b[15]) * z + b[16]) * z + b[17]) * z + b[18]) * z + b[19])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_3.hpp b/include/boost/math/tools/detail/rational_horner1_3.hpp new file mode 100644 index 000000000..ac1b785e9 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_3.hpp @@ -0,0 +1,54 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_3_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_4.hpp b/include/boost/math/tools/detail/rational_horner1_4.hpp new file mode 100644 index 000000000..eeced600f --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_4.hpp @@ -0,0 +1,66 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_4_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_5.hpp b/include/boost/math/tools/detail/rational_horner1_5.hpp new file mode 100644 index 000000000..0479f6637 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_5.hpp @@ -0,0 +1,78 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_5_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_6.hpp b/include/boost/math/tools/detail/rational_horner1_6.hpp new file mode 100644 index 000000000..db259968e --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_6.hpp @@ -0,0 +1,90 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_6_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_7.hpp b/include/boost/math/tools/detail/rational_horner1_7.hpp new file mode 100644 index 000000000..b431fe91e --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_7.hpp @@ -0,0 +1,102 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_7_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_8.hpp b/include/boost/math/tools/detail/rational_horner1_8.hpp new file mode 100644 index 000000000..5a04a7a34 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_8.hpp @@ -0,0 +1,114 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_8_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner1_9.hpp b/include/boost/math/tools/detail/rational_horner1_9.hpp new file mode 100644 index 000000000..4b5465fc4 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner1_9.hpp @@ -0,0 +1,126 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using Horners rule +#ifndef BOOST_MATH_TOOLS_POLY_RAT_9_HPP +#define BOOST_MATH_TOOLS_POLY_RAT_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T*, const U*, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + if(x <= 1) + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); + else + { + V z = 1 / x; + return static_cast((a[0] * z + a[1]) / (b[0] * z + b[1])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + if(x <= 1) + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((a[0] * z + a[1]) * z + a[2]) / ((b[0] * z + b[1]) * z + b[2])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + if(x <= 1) + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) / (((b[0] * z + b[1]) * z + b[2]) * z + b[3])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + return static_cast(((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((b[4] * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) / ((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + return static_cast((((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((b[5] * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) / (((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + return static_cast(((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((b[6] * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) / ((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + return static_cast((((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / (((((((b[7] * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) / (((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + return static_cast(((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]) / ((((((((b[8] * x + b[7]) * x + b[6]) * x + b[5]) * x + b[4]) * x + b[3]) * x + b[2]) * x + b[1]) * x + b[0])); + else + { + V z = 1 / x; + return static_cast(((((((((a[0] * z + a[1]) * z + a[2]) * z + a[3]) * z + a[4]) * z + a[5]) * z + a[6]) * z + a[7]) * z + a[8]) / ((((((((b[0] * z + b[1]) * z + b[2]) * z + b[3]) * z + b[4]) * z + b[5]) * z + b[6]) * z + b[7]) * z + b[8])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_10.hpp b/include/boost/math/tools/detail/rational_horner2_10.hpp new file mode 100644 index 000000000..db752742d --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_10.hpp @@ -0,0 +1,144 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_10_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_11.hpp b/include/boost/math/tools/detail/rational_horner2_11.hpp new file mode 100644 index 000000000..2b728e8b4 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_11.hpp @@ -0,0 +1,160 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_11_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_12.hpp b/include/boost/math/tools/detail/rational_horner2_12.hpp new file mode 100644 index 000000000..daa14e4d2 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_12.hpp @@ -0,0 +1,176 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_12_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_13.hpp b/include/boost/math/tools/detail/rational_horner2_13.hpp new file mode 100644 index 000000000..e5dfc6228 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_13.hpp @@ -0,0 +1,192 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_13_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_14.hpp b/include/boost/math/tools/detail/rational_horner2_14.hpp new file mode 100644 index 000000000..37ddfa5e6 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_14.hpp @@ -0,0 +1,208 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_14_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_15.hpp b/include/boost/math/tools/detail/rational_horner2_15.hpp new file mode 100644 index 000000000..9168b2efc --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_15.hpp @@ -0,0 +1,224 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_15_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_16.hpp b/include/boost/math/tools/detail/rational_horner2_16.hpp new file mode 100644 index 000000000..7dafa460a --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_16.hpp @@ -0,0 +1,240 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_16_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_17.hpp b/include/boost/math/tools/detail/rational_horner2_17.hpp new file mode 100644 index 000000000..06330599d --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_17.hpp @@ -0,0 +1,256 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_17_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16] + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16] + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_18.hpp b/include/boost/math/tools/detail/rational_horner2_18.hpp new file mode 100644 index 000000000..78584e037 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_18.hpp @@ -0,0 +1,272 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_18_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16] + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16] + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((((b[17] * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) / (((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_19.hpp b/include/boost/math/tools/detail/rational_horner2_19.hpp new file mode 100644 index 000000000..592e9edbc --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_19.hpp @@ -0,0 +1,288 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_19_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16] + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16] + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((((b[17] * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) / (((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((((b[18] * x2 + b[16]) * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((((b[17] * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z2 + a[18] + ((((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) * z) / (((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z2 + b[18] + ((((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_2.hpp b/include/boost/math/tools/detail/rational_horner2_2.hpp new file mode 100644 index 000000000..c5400a0d1 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_2.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_2_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_20.hpp b/include/boost/math/tools/detail/rational_horner2_20.hpp new file mode 100644 index 000000000..7f8f5d6a0 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_20.hpp @@ -0,0 +1,304 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_20_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((a[9] * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((b[9] * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10] + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z) / (((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10] + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((a[10] * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((b[10] * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z + ((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z + ((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((a[11] * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((b[11] * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12] + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z) / ((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12] + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((a[12] * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((b[12] * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z + (((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z + (((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((a[13] * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((b[13] * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14] + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z) / (((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14] + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((a[14] * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((b[14] * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z + ((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z + ((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((((((a[15] * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((((((b[15] * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16] + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z) / ((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16] + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + (((((((a[16] * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / (((((((((b[17] * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + (((((((b[16] * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z + (((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) / (((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z + (((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((((((((a[17] * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / (((((((((b[18] * x2 + b[16]) * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((((((((b[17] * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z2 + a[18] + ((((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) * z) / (((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z2 + b[18] + ((((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<20>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((((((((a[19] * x2 + a[17]) * x2 + a[15]) * x2 + a[13]) * x2 + a[11]) * x2 + a[9]) * x2 + a[7]) * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((((((((a[18] * x2 + a[16]) * x2 + a[14]) * x2 + a[12]) * x2 + a[10]) * x2 + a[8]) * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((((((((b[19] * x2 + b[17]) * x2 + b[15]) * x2 + b[13]) * x2 + b[11]) * x2 + b[9]) * x2 + b[7]) * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((((((((b[18] * x2 + b[16]) * x2 + b[14]) * x2 + b[12]) * x2 + b[10]) * x2 + b[8]) * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((((((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8]) * z2 + a[10]) * z2 + a[12]) * z2 + a[14]) * z2 + a[16]) * z2 + a[18]) * z + ((((((((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z2 + a[9]) * z2 + a[11]) * z2 + a[13]) * z2 + a[15]) * z2 + a[17]) * z2 + a[19]) / ((((((((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8]) * z2 + b[10]) * z2 + b[12]) * z2 + b[14]) * z2 + b[16]) * z2 + b[18]) * z + ((((((((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z2 + b[9]) * z2 + b[11]) * z2 + b[13]) * z2 + b[15]) * z2 + b[17]) * z2 + b[19])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_3.hpp b/include/boost/math/tools/detail/rational_horner2_3.hpp new file mode 100644 index 000000000..645c3c364 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_3.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_3_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_4.hpp b/include/boost/math/tools/detail/rational_horner2_4.hpp new file mode 100644 index 000000000..781b4c109 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_4.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_4_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_5.hpp b/include/boost/math/tools/detail/rational_horner2_5.hpp new file mode 100644 index 000000000..a11d0d643 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_5.hpp @@ -0,0 +1,64 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_5_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_6.hpp b/include/boost/math/tools/detail/rational_horner2_6.hpp new file mode 100644 index 000000000..596bc115c --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_6.hpp @@ -0,0 +1,80 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_6_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_7.hpp b/include/boost/math/tools/detail/rational_horner2_7.hpp new file mode 100644 index 000000000..28998d2c9 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_7.hpp @@ -0,0 +1,96 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_7_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_8.hpp b/include/boost/math/tools/detail/rational_horner2_8.hpp new file mode 100644 index 000000000..1405c432f --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_8.hpp @@ -0,0 +1,112 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_8_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner2_9.hpp b/include/boost/math/tools/detail/rational_horner2_9.hpp new file mode 100644 index 000000000..5a537ef4e --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner2_9.hpp @@ -0,0 +1,128 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_9_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((a[4] * x2 + a[2]) * x2 + a[0] + (a[3] * x2 + a[1]) * x) / ((b[4] * x2 + b[2]) * x2 + b[0] + (b[3] * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((a[0] * z2 + a[2]) * z2 + a[4] + (a[1] * z2 + a[3]) * z) / ((b[0] * z2 + b[2]) * z2 + b[4] + (b[1] * z2 + b[3]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[5] * x2 + a[3]) * x2 + a[1]) * x + (a[4] * x2 + a[2]) * x2 + a[0]) / (((b[5] * x2 + b[3]) * x2 + b[1]) * x + (b[4] * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z + (a[1] * z2 + a[3]) * z2 + a[5]) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z + (b[1] * z2 + b[3]) * z2 + b[5])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast((((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + ((a[5] * x2 + a[3]) * x2 + a[1]) * x) / (((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + ((b[5] * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6] + ((a[1] * z2 + a[3]) * z2 + a[5]) * z) / (((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6] + ((b[1] * z2 + b[3]) * z2 + b[5]) * z)); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x + ((a[6] * x2 + a[4]) * x2 + a[2]) * x2 + a[0]) / ((((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x + ((b[6] * x2 + b[4]) * x2 + b[2]) * x2 + b[0])); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z + ((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z + ((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7])); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + return static_cast(((((a[8] * x2 + a[6]) * x2 + a[4]) * x2 + a[2]) * x2 + a[0] + (((a[7] * x2 + a[5]) * x2 + a[3]) * x2 + a[1]) * x) / ((((b[8] * x2 + b[6]) * x2 + b[4]) * x2 + b[2]) * x2 + b[0] + (((b[7] * x2 + b[5]) * x2 + b[3]) * x2 + b[1]) * x)); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + return static_cast(((((a[0] * z2 + a[2]) * z2 + a[4]) * z2 + a[6]) * z2 + a[8] + (((a[1] * z2 + a[3]) * z2 + a[5]) * z2 + a[7]) * z) / ((((b[0] * z2 + b[2]) * z2 + b[4]) * z2 + b[6]) * z2 + b[8] + (((b[1] * z2 + b[3]) * z2 + b[5]) * z2 + b[7]) * z)); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_10.hpp b/include/boost/math/tools/detail/rational_horner3_10.hpp new file mode 100644 index 000000000..205077c2d --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_10.hpp @@ -0,0 +1,396 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_10_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_10_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_11.hpp b/include/boost/math/tools/detail/rational_horner3_11.hpp new file mode 100644 index 000000000..05ed555c2 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_11.hpp @@ -0,0 +1,482 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_11_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_11_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_12.hpp b/include/boost/math/tools/detail/rational_horner3_12.hpp new file mode 100644 index 000000000..88d6d9402 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_12.hpp @@ -0,0 +1,576 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_12_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_12_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_13.hpp b/include/boost/math/tools/detail/rational_horner3_13.hpp new file mode 100644 index 000000000..8f1661a88 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_13.hpp @@ -0,0 +1,678 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_13_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_13_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_14.hpp b/include/boost/math/tools/detail/rational_horner3_14.hpp new file mode 100644 index 000000000..299617339 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_14.hpp @@ -0,0 +1,788 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_14_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_14_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_15.hpp b/include/boost/math/tools/detail/rational_horner3_15.hpp new file mode 100644 index 000000000..67b71b42c --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_15.hpp @@ -0,0 +1,906 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_15_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_15_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_16.hpp b/include/boost/math/tools/detail/rational_horner3_16.hpp new file mode 100644 index 000000000..75cb17a60 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_16.hpp @@ -0,0 +1,1032 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_16_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_16_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[2] = b[15] * x2 + b[13]; + t[3] = b[14] * x2 + b[12]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_17.hpp b/include/boost/math/tools/detail/rational_horner3_17.hpp new file mode 100644 index 000000000..275236412 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_17.hpp @@ -0,0 +1,1166 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_17_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_17_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[2] = b[15] * x2 + b[13]; + t[3] = b[14] * x2 + b[12]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[16] * x2 + a[14]; + t[1] = a[15] * x2 + a[13]; + t[2] = b[16] * x2 + b[14]; + t[3] = b[15] * x2 + b[13]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[16]); + t[2] += static_cast(b[16]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_18.hpp b/include/boost/math/tools/detail/rational_horner3_18.hpp new file mode 100644 index 000000000..19e0a5337 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_18.hpp @@ -0,0 +1,1308 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_18_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_18_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[2] = b[15] * x2 + b[13]; + t[3] = b[14] * x2 + b[12]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[16] * x2 + a[14]; + t[1] = a[15] * x2 + a[13]; + t[2] = b[16] * x2 + b[14]; + t[3] = b[15] * x2 + b[13]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[16]); + t[2] += static_cast(b[16]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[2] = b[17] * x2 + b[15]; + t[3] = b[16] * x2 + b[14]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[2] += static_cast(b[13]); + t[3] += static_cast(b[12]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_19.hpp b/include/boost/math/tools/detail/rational_horner3_19.hpp new file mode 100644 index 000000000..ff7156c80 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_19.hpp @@ -0,0 +1,1458 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_19_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_19_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[2] = b[15] * x2 + b[13]; + t[3] = b[14] * x2 + b[12]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[16] * x2 + a[14]; + t[1] = a[15] * x2 + a[13]; + t[2] = b[16] * x2 + b[14]; + t[3] = b[15] * x2 + b[13]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[16]); + t[2] += static_cast(b[16]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[2] = b[17] * x2 + b[15]; + t[3] = b[16] * x2 + b[14]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[2] += static_cast(b[13]); + t[3] += static_cast(b[12]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[18] * x2 + a[16]; + t[1] = a[17] * x2 + a[15]; + t[2] = b[18] * x2 + b[16]; + t[3] = b[17] * x2 + b[15]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[13]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[18]); + t[2] += static_cast(b[18]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_2.hpp b/include/boost/math/tools/detail/rational_horner3_2.hpp new file mode 100644 index 000000000..c5400a0d1 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_2.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_2_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_2_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_20.hpp b/include/boost/math/tools/detail/rational_horner3_20.hpp new file mode 100644 index 000000000..a5948d2ff --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_20.hpp @@ -0,0 +1,1616 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_20_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_20_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<10>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[9] * x2 + a[7]; + t[1] = a[8] * x2 + a[6]; + t[2] = b[9] * x2 + b[7]; + t[3] = b[8] * x2 + b[6]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<11>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[10] * x2 + a[8]; + t[1] = a[9] * x2 + a[7]; + t[2] = b[10] * x2 + b[8]; + t[3] = b[9] * x2 + b[7]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[10]); + t[2] += static_cast(b[10]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<12>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[11] * x2 + a[9]; + t[1] = a[10] * x2 + a[8]; + t[2] = b[11] * x2 + b[9]; + t[3] = b[10] * x2 + b[8]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<13>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[12] * x2 + a[10]; + t[1] = a[11] * x2 + a[9]; + t[2] = b[12] * x2 + b[10]; + t[3] = b[11] * x2 + b[9]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[12]); + t[2] += static_cast(b[12]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<14>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[13] * x2 + a[11]; + t[1] = a[12] * x2 + a[10]; + t[2] = b[13] * x2 + b[11]; + t[3] = b[12] * x2 + b[10]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<15>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[14] * x2 + a[12]; + t[1] = a[13] * x2 + a[11]; + t[2] = b[14] * x2 + b[12]; + t[3] = b[13] * x2 + b[11]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[14]); + t[2] += static_cast(b[14]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<16>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[15] * x2 + a[13]; + t[1] = a[14] * x2 + a[12]; + t[2] = b[15] * x2 + b[13]; + t[3] = b[14] * x2 + b[12]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<17>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[16] * x2 + a[14]; + t[1] = a[15] * x2 + a[13]; + t[2] = b[16] * x2 + b[14]; + t[3] = b[15] * x2 + b[13]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[16]); + t[2] += static_cast(b[16]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<18>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[17] * x2 + a[15]; + t[1] = a[16] * x2 + a[14]; + t[2] = b[17] * x2 + b[15]; + t[3] = b[16] * x2 + b[14]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[2] += static_cast(b[13]); + t[3] += static_cast(b[12]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<19>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[18] * x2 + a[16]; + t[1] = a[17] * x2 + a[15]; + t[2] = b[18] * x2 + b[16]; + t[3] = b[17] * x2 + b[15]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[13]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[11]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[9]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[7]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[5]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[18]); + t[2] += static_cast(b[18]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<20>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[19] * x2 + a[17]; + t[1] = a[18] * x2 + a[16]; + t[2] = b[19] * x2 + b[17]; + t[3] = b[18] * x2 + b[16]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[15]); + t[1] += static_cast(a[14]); + t[2] += static_cast(b[15]); + t[3] += static_cast(b[14]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[13]); + t[1] += static_cast(a[12]); + t[2] += static_cast(b[13]); + t[3] += static_cast(b[12]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[11]); + t[1] += static_cast(a[10]); + t[2] += static_cast(b[11]); + t[3] += static_cast(b[10]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[9]); + t[1] += static_cast(a[8]); + t[2] += static_cast(b[9]); + t[3] += static_cast(b[8]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[7]); + t[1] += static_cast(a[6]); + t[2] += static_cast(b[7]); + t[3] += static_cast(b[6]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[5]); + t[1] += static_cast(a[4]); + t[2] += static_cast(b[5]); + t[3] += static_cast(b[4]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[8]); + t[1] += static_cast(a[9]); + t[2] += static_cast(b[8]); + t[3] += static_cast(b[9]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[10]); + t[1] += static_cast(a[11]); + t[2] += static_cast(b[10]); + t[3] += static_cast(b[11]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[12]); + t[1] += static_cast(a[13]); + t[2] += static_cast(b[12]); + t[3] += static_cast(b[13]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[14]); + t[1] += static_cast(a[15]); + t[2] += static_cast(b[14]); + t[3] += static_cast(b[15]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[16]); + t[1] += static_cast(a[17]); + t[2] += static_cast(b[16]); + t[3] += static_cast(b[17]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[18]); + t[1] += static_cast(a[19]); + t[2] += static_cast(b[18]); + t[3] += static_cast(b[19]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_3.hpp b/include/boost/math/tools/detail/rational_horner3_3.hpp new file mode 100644 index 000000000..645c3c364 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_3.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_3_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_3_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_4.hpp b/include/boost/math/tools/detail/rational_horner3_4.hpp new file mode 100644 index 000000000..781b4c109 --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_4.hpp @@ -0,0 +1,48 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_4_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_4_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_5.hpp b/include/boost/math/tools/detail/rational_horner3_5.hpp new file mode 100644 index 000000000..333b7fd2e --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_5.hpp @@ -0,0 +1,86 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_5_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_5_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_6.hpp b/include/boost/math/tools/detail/rational_horner3_6.hpp new file mode 100644 index 000000000..33e075b6a --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_6.hpp @@ -0,0 +1,132 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_6_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_6_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_7.hpp b/include/boost/math/tools/detail/rational_horner3_7.hpp new file mode 100644 index 000000000..6f886d16d --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_7.hpp @@ -0,0 +1,186 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_7_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_7_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_8.hpp b/include/boost/math/tools/detail/rational_horner3_8.hpp new file mode 100644 index 000000000..062f9d3cb --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_8.hpp @@ -0,0 +1,248 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_8_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_8_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/detail/rational_horner3_9.hpp b/include/boost/math/tools/detail/rational_horner3_9.hpp new file mode 100644 index 000000000..5c47864eb --- /dev/null +++ b/include/boost/math/tools/detail/rational_horner3_9.hpp @@ -0,0 +1,318 @@ +// (C) Copyright John Maddock 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This file is machine generated, do not edit by hand + +// Polynomial evaluation using second order Horners rule +#ifndef BOOST_MATH_TOOLS_RAT_EVAL_9_HPP +#define BOOST_MATH_TOOLS_RAT_EVAL_9_HPP + +namespace boost{ namespace math{ namespace tools{ namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<0>*) +{ + return static_cast(0); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V&, const mpl::int_<1>*) +{ + return static_cast(a[0]) / static_cast(b[0]); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<2>*) +{ + return static_cast((a[1] * x + a[0]) / (b[1] * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<3>*) +{ + return static_cast(((a[2] * x + a[1]) * x + a[0]) / ((b[2] * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<4>*) +{ + return static_cast((((a[3] * x + a[2]) * x + a[1]) * x + a[0]) / (((b[3] * x + b[2]) * x + b[1]) * x + b[0])); +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<5>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[4] * x2 + a[2]; + t[1] = a[3] * x2 + a[1]; + t[2] = b[4] * x2 + b[2]; + t[3] = b[3] * x2 + b[1]; + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[4]); + t[2] += static_cast(b[4]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<6>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[5] * x2 + a[3]; + t[1] = a[4] * x2 + a[2]; + t[2] = b[5] * x2 + b[3]; + t[3] = b[4] * x2 + b[2]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<7>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[6] * x2 + a[4]; + t[1] = a[5] * x2 + a[3]; + t[2] = b[6] * x2 + b[4]; + t[3] = b[5] * x2 + b[3]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[6]); + t[2] += static_cast(b[6]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<8>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[7] * x2 + a[5]; + t[1] = a[6] * x2 + a[4]; + t[2] = b[7] * x2 + b[5]; + t[3] = b[6] * x2 + b[4]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[3]); + t[1] += static_cast(a[2]); + t[2] += static_cast(b[3]); + t[3] += static_cast(b[2]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[1]); + t[1] += static_cast(a[0]); + t[2] += static_cast(b[1]); + t[3] += static_cast(b[0]); + t[0] *= x; + t[2] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z; + t[2] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + +template +inline V evaluate_rational_c_imp(const T* a, const U* b, const V& x, const mpl::int_<9>*) +{ + if(x <= 1) + { + V x2 = x * x; + V t[4]; + t[0] = a[8] * x2 + a[6]; + t[1] = a[7] * x2 + a[5]; + t[2] = b[8] * x2 + b[6]; + t[3] = b[7] * x2 + b[5]; + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[3]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[3]); + t[0] *= x2; + t[1] *= x2; + t[2] *= x2; + t[3] *= x2; + t[0] += static_cast(a[2]); + t[1] += static_cast(a[1]); + t[2] += static_cast(b[2]); + t[3] += static_cast(b[1]); + t[0] *= x2; + t[2] *= x2; + t[0] += static_cast(a[0]); + t[2] += static_cast(b[0]); + t[1] *= x; + t[3] *= x; + return (t[0] + t[1]) / (t[2] + t[3]); + } + else + { + V z = 1 / x; + V z2 = 1 / (x * x); + V t[4]; + t[0] = a[0] * z2 + a[2]; + t[1] = a[1] * z2 + a[3]; + t[2] = b[0] * z2 + b[2]; + t[3] = b[1] * z2 + b[3]; + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[4]); + t[1] += static_cast(a[5]); + t[2] += static_cast(b[4]); + t[3] += static_cast(b[5]); + t[0] *= z2; + t[1] *= z2; + t[2] *= z2; + t[3] *= z2; + t[0] += static_cast(a[6]); + t[1] += static_cast(a[7]); + t[2] += static_cast(b[6]); + t[3] += static_cast(b[7]); + t[0] *= z2; + t[2] *= z2; + t[0] += static_cast(a[8]); + t[2] += static_cast(b[8]); + t[1] *= z; + t[3] *= z; + return (t[0] + t[1]) / (t[2] + t[3]); + } +} + + +}}}} // namespaces + +#endif // include guard + diff --git a/include/boost/math/tools/fraction.hpp b/include/boost/math/tools/fraction.hpp new file mode 100644 index 000000000..f5b3df5a4 --- /dev/null +++ b/include/boost/math/tools/fraction.hpp @@ -0,0 +1,259 @@ +// (C) Copyright John Maddock 2005-2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_FRACTION_INCLUDED +#define BOOST_MATH_TOOLS_FRACTION_INCLUDED + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +namespace detail +{ + + template + struct is_pair : public boost::false_type{}; + + template + struct is_pair > : public boost::true_type{}; + + template + struct fraction_traits_simple + { + typedef typename Gen::result_type result_type; + typedef typename Gen::result_type value_type; + + static result_type a(const value_type& v) + { + return 1; + } + static result_type b(const value_type& v) + { + return v; + } + }; + + template + struct fraction_traits_pair + { + typedef typename Gen::result_type value_type; + typedef typename value_type::first_type result_type; + + static result_type a(const value_type& v) + { + return v.first; + } + static result_type b(const value_type& v) + { + return v.second; + } + }; + + template + struct fraction_traits + : public boost::mpl::if_c< + is_pair::value, + fraction_traits_pair, + fraction_traits_simple >::type + { + }; + +} // namespace detail + +// +// continued_fraction_b +// Evaluates: +// +// b0 + a1 +// --------------- +// b1 + a2 +// ---------- +// b2 + a3 +// ----- +// b3 + ... +// +// Note that the first a0 returned by generator Gen is disarded. +// +template +typename detail::fraction_traits::result_type continued_fraction_b(Gen& g, int bits) +{ + BOOST_MATH_STD_USING // ADL of std names + + typedef detail::fraction_traits traits; + typedef typename traits::result_type result_type; + typedef typename traits::value_type value_type; + + result_type factor = ldexp(1.0f, 1 - bits); // 1 / pow(result_type(2), bits); + result_type tiny = tools::min_value(); + + value_type v = g(); + + result_type f, C, D, delta; + f = traits::b(v); + if(f == 0) + f = tiny; + C = f; + D = 0; + + do{ + v = g(); + D = traits::b(v) + traits::a(v) * D; + if(D == 0) + D = tiny; + C = traits::b(v) + traits::a(v) / C; + if(C == 0) + C = tiny; + D = 1/D; + delta = C*D; + f = f * delta; + }while(fabs(delta - 1) > factor); + + return f; +} + +template +typename detail::fraction_traits::result_type continued_fraction_b(Gen& g, int bits, boost::uintmax_t& max_terms) +{ + BOOST_MATH_STD_USING // ADL of std names + + typedef detail::fraction_traits traits; + typedef typename traits::result_type result_type; + typedef typename traits::value_type value_type; + + result_type factor = ldexp(1.0f, 1 - bits); // 1 / pow(result_type(2), bits); + result_type tiny = tools::min_value(); + + value_type v = g(); + + result_type f, C, D, delta; + f = traits::b(v); + if(f == 0) + f = tiny; + C = f; + D = 0; + + boost::uintmax_t counter(max_terms); + + do{ + v = g(); + D = traits::b(v) + traits::a(v) * D; + if(D == 0) + D = tiny; + C = traits::b(v) + traits::a(v) / C; + if(C == 0) + C = tiny; + D = 1/D; + delta = C*D; + f = f * delta; + }while((fabs(delta - 1) > factor) && --counter); + + max_terms = max_terms - counter; + + return f; +} + +// +// continued_fraction_a +// Evaluates: +// +// a1 +// --------------- +// b1 + a2 +// ---------- +// b2 + a3 +// ----- +// b3 + ... +// +// Note that the first a1 and b1 returned by generator Gen are both used. +// +template +typename detail::fraction_traits::result_type continued_fraction_a(Gen& g, int bits) +{ + BOOST_MATH_STD_USING // ADL of std names + + typedef detail::fraction_traits traits; + typedef typename traits::result_type result_type; + typedef typename traits::value_type value_type; + + result_type factor = ldexp(1.0f, 1-bits); // 1 / pow(result_type(2), bits); + result_type tiny = tools::min_value(); + + value_type v = g(); + + result_type f, C, D, delta, a0; + f = traits::b(v); + a0 = traits::a(v); + if(f == 0) + f = tiny; + C = f; + D = 0; + + do{ + v = g(); + D = traits::b(v) + traits::a(v) * D; + if(D == 0) + D = tiny; + C = traits::b(v) + traits::a(v) / C; + if(C == 0) + C = tiny; + D = 1/D; + delta = C*D; + f = f * delta; + }while(fabs(delta - 1) > factor); + + return a0/f; +} + +template +typename detail::fraction_traits::result_type continued_fraction_a(Gen& g, int bits, boost::uintmax_t& max_terms) +{ + BOOST_MATH_STD_USING // ADL of std names + + typedef detail::fraction_traits traits; + typedef typename traits::result_type result_type; + typedef typename traits::value_type value_type; + + result_type factor = ldexp(1.0f, 1-bits); // 1 / pow(result_type(2), bits); + result_type tiny = tools::min_value(); + + value_type v = g(); + + result_type f, C, D, delta, a0; + f = traits::b(v); + a0 = traits::a(v); + if(f == 0) + f = tiny; + C = f; + D = 0; + + boost::uintmax_t counter(max_terms); + + do{ + v = g(); + D = traits::b(v) + traits::a(v) * D; + if(D == 0) + D = tiny; + C = traits::b(v) + traits::a(v) / C; + if(C == 0) + C = tiny; + D = 1/D; + delta = C*D; + f = f * delta; + }while((fabs(delta - 1) > factor) && --counter); + + max_terms = max_terms - counter; + + return a0/f; +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_FRACTION_INCLUDED diff --git a/include/boost/math/tools/minima.hpp b/include/boost/math/tools/minima.hpp new file mode 100644 index 000000000..14ec95795 --- /dev/null +++ b/include/boost/math/tools/minima.hpp @@ -0,0 +1,147 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_MATH_TOOLS_MINIMA_HPP +#define BOOST_MATH_TOOLS_MINIMA_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +template +std::pair brent_find_minima(F f, T min, T max, int bits, boost::uintmax_t& max_iter) +{ + BOOST_MATH_STD_USING + bits = (std::min)(policies::digits >() / 2, bits); + T tolerance = static_cast(ldexp(1.0, 1-bits)); + T x; // minima so far + T w; // second best point + T v; // previous value of w + T u; // most recent evaluation point + T delta; // The distance moved in the last step + T delta2; // The distance moved in the step before last + T fu, fv, fw, fx; // function evaluations at u, v, w, x + T mid; // midpoint of min and max + T fract1, fract2; // minimal relative movement in x + + static const T golden = 0.3819660f; // golden ratio, don't need too much precision here! + + x = w = v = max; + fw = fv = fx = f(x); + delta2 = delta = 0; + + uintmax_t count = max_iter; + + do{ + // get midpoint + mid = (min + max) / 2; + // work out if we're done already: + fract1 = tolerance * fabs(x) + tolerance / 4; + fract2 = 2 * fract1; + if(fabs(x - mid) <= (fract2 - (max - min) / 2)) + break; + + if(fabs(delta2) > fract1) + { + // try and construct a parabolic fit: + T r = (x - w) * (fx - fv); + T q = (x - v) * (fx - fw); + T p = (x - v) * q - (x - w) * r; + q = 2 * (q - r); + if(q > 0) + p = -p; + q = fabs(q); + T td = delta2; + delta2 = delta; + // determine whether a parabolic step is acceptible or not: + if((fabs(p) >= fabs(q * td / 2)) || (p <= q * (min - x)) || (p >= q * (max - x))) + { + // nope, try golden section instead + delta2 = (x >= mid) ? min - x : max - x; + delta = golden * delta2; + } + else + { + // whew, parabolic fit: + delta = p / q; + u = x + delta; + if(((u - min) < fract2) || ((max- u) < fract2)) + delta = (mid - x) < 0 ? -fabs(fract1) : fabs(fract1); + } + } + else + { + // golden section: + delta2 = (x >= mid) ? min - x : max - x; + delta = golden * delta2; + } + // update current position: + u = (fabs(delta) >= fract1) ? x + delta : (delta > 0 ? x + fabs(fract1) : x - fabs(fract1)); + fu = f(u); + if(fu <= fx) + { + // good new point is an improvement! + // update brackets: + if(u >= x) + min = x; + else + max = x; + // update control points: + v = w; + w = x; + x = u; + fv = fw; + fw = fx; + fx = fu; + } + else + { + // Oh dear, point u is worse than what we have already, + // even so it *must* be better than one of our endpoints: + if(u < x) + min = u; + else + max = u; + if((fu <= fw) || (w == x)) + { + // however it is at least second best: + v = w; + w = u; + fv = fw; + fw = fu; + } + else if((fu <= fv) || (v == x) || (v == w)) + { + // third best: + v = u; + fv = fu; + } + } + + }while(--count); + + max_iter -= count; + + return std::make_pair(x, fx); +} + +template +inline std::pair brent_find_minima(F f, T min, T max, int digits) +{ + boost::uintmax_t m = (std::numeric_limits::max)(); + return brent_find_minima(f, min, max, digits, m); +} + +}}} // namespaces + +#endif + + + diff --git a/include/boost/math/tools/polynomial.hpp b/include/boost/math/tools/polynomial.hpp new file mode 100644 index 000000000..c2d5a091c --- /dev/null +++ b/include/boost/math/tools/polynomial.hpp @@ -0,0 +1,234 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP +#define BOOST_MATH_TOOLS_POLYNOMIAL_HPP + +#include +#include +#include + +#include + +namespace boost{ namespace math{ namespace tools{ + +template +class polynomial +{ +public: + // typedefs: + typedef typename std::vector::value_type value_type; + typedef typename std::vector::size_type size_type; + + // construct: + polynomial(){} + template + polynomial(const U* data, unsigned order) + : m_data(data, data + order + 1) + { + } + template + polynomial(const U& point) + { + m_data.push_back(point); + } + + // copy: + polynomial(const polynomial& p) + : m_data(p.m_data) { } + + template + polynomial(const polynomial& p) + { + for(unsigned i = 0; i < p.size(); ++i) + { + m_data.push_back(boost::math::tools::real_cast(p[i])); + } + } + + // access: + size_type size()const { return m_data.size(); } + size_type degree()const { return m_data.size() - 1; } + value_type& operator[](size_type i) + { + return m_data[i]; + } + const value_type& operator[](size_type i)const + { + return m_data[i]; + } + T evaluate(T z)const + { + return boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size());; + } + + // operators: + template + polynomial& operator +=(const U& value) + { + if(m_data.size() == 0) + m_data.push_back(value); + else + { + m_data[0] += value; + } + return *this; + } + template + polynomial& operator -=(const U& value) + { + if(m_data.size() == 0) + m_data.push_back(-value); + else + { + m_data[0] -= value; + } + return *this; + } + template + polynomial& operator *=(const U& value) + { + for(size_type i = 0; i < m_data.size(); ++i) + m_data[i] *= value; + return *this; + } + template + polynomial& operator +=(const polynomial& value) + { + size_type s1 = (std::min)(m_data.size(), value.size()); + for(size_type i = 0; i < s1; ++i) + m_data[i] += value[i]; + for(size_type i = s1; i < value.size(); ++i) + m_data.push_back(value[i]); + return *this; + } + template + polynomial& operator -=(const polynomial& value) + { + size_type s1 = (std::min)(m_data.size(), value.size()); + for(size_type i = 0; i < s1; ++i) + m_data[i] -= value[i]; + for(size_type i = s1; i < value.size(); ++i) + m_data.push_back(-value[i]); + return *this; + } + template + polynomial& operator *=(const polynomial& value) + { + // TODO: FIXME: use O(N log(N)) algorithm!!! + BOOST_ASSERT(value.size()); + polynomial base(*this); + *this *= value[0]; + for(size_type i = 1; i < value.size(); ++i) + { + polynomial t(base); + t *= value[i]; + size_type s = size() - i; + for(size_type j = 0; j < s; ++j) + { + m_data[i+j] += t[j]; + } + for(size_type j = s; j < t.size(); ++j) + m_data.push_back(t[j]); + } + return *this; + } + +private: + std::vector m_data; +}; + +template +inline polynomial operator + (const polynomial& a, const polynomial& b) +{ + polynomial result(a); + result += b; + return result; +} + +template +inline polynomial operator - (const polynomial& a, const polynomial& b) +{ + polynomial result(a); + result -= b; + return result; +} + +template +inline polynomial operator * (const polynomial& a, const polynomial& b) +{ + polynomial result(a); + result *= b; + return result; +} + +template +inline polynomial operator + (const polynomial& a, const U& b) +{ + polynomial result(a); + result += b; + return result; +} + +template +inline polynomial operator - (const polynomial& a, const U& b) +{ + polynomial result(a); + result -= b; + return result; +} + +template +inline polynomial operator * (const polynomial& a, const U& b) +{ + polynomial result(a); + result *= b; + return result; +} + +template +inline polynomial operator + (const U& a, const polynomial& b) +{ + polynomial result(b); + result += a; + return result; +} + +template +inline polynomial operator - (const U& a, const polynomial& b) +{ + polynomial result(a); + result -= b; + return result; +} + +template +inline polynomial operator * (const U& a, const polynomial& b) +{ + polynomial result(b); + result *= a; + return result; +} + +template +inline std::basic_ostream& operator << (std::basic_ostream& os, const polynomial& poly) +{ + os << "{ "; + for(unsigned i = 0; i < poly.size(); ++i) + { + if(i) os << ", "; + os << poly[i]; + } + os << " }"; + return os; +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP + + diff --git a/include/boost/math/tools/precision.hpp b/include/boost/math/tools/precision.hpp new file mode 100644 index 000000000..759761ba2 --- /dev/null +++ b/include/boost/math/tools/precision.hpp @@ -0,0 +1,235 @@ +// Copyright John Maddock 2005-2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_PRECISION_INCLUDED +#define BOOST_MATH_TOOLS_PRECISION_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +// These two are for LDBL_MAN_DIG: +#include +#include + +namespace boost{ namespace math +{ +namespace tools +{ +// If T is not specialized, the functions digits, max_value and min_value, +// all get synthesised automatically from std::numeric_limits. +// However, if numeric_limits is not specialised for type RealType, +// for example with NTL::RR type, then you will get a compiler error +// when code tries to use these functions, unless you explicitly specialise them. + +// For example if the precision of RealType varies at runtime, +// then numeric_limits support may not be appropriate, +// see boost/math/tools/ntl.hpp for examples like +// template <> NTL::RR max_value ... +// See Conceptual Requirements for Real Number Types. + +template +inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + return std::numeric_limits::digits; +} + +template +inline T max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + return (std::numeric_limits::max)(); +} // Also used as a finite 'infinite' value for - and +infinity, for example: +// -max_value = -1.79769e+308, max_value = 1.79769e+308. + +template +inline T min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + return (std::numeric_limits::min)(); +} + +namespace detail{ +// +// Logarithmic limits come next, note that although +// we can compute these from the log of the max value +// that is not in general thread safe (if we cache the value) +// so it's better to specialise these: +// +// For type float first: +// +template +inline T log_max_value(const mpl::int_<128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return 88.0f; +} + +template +inline T log_min_value(const mpl::int_<128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return -87.0f; +} +// +// Now double: +// +template +inline T log_max_value(const mpl::int_<1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return 709.0; +} + +template +inline T log_min_value(const mpl::int_<1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return -708.0; +} +// +// 80 and 128-bit long doubles: +// +template +inline T log_max_value(const mpl::int_<16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return 11356.0L; +} + +template +inline T log_min_value(const mpl::int_<16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return -11355.0L; +} + +template +inline T log_max_value(const mpl::int_<0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + BOOST_MATH_STD_USING + static const T val = log((std::numeric_limits::max)()); + return val; +} + +template +inline T log_min_value(const mpl::int_<0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); +#endif + BOOST_MATH_STD_USING + static const T val = log((std::numeric_limits::max)()); + return val; +} + +template +inline T epsilon(const mpl::true_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + return std::numeric_limits::epsilon(); +} + +#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106)) +template <> +inline long double epsilon(const mpl::true_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(long double)) +{ + // numeric_limits on Darwin tells lies here. + // This static assert fails for some unknown reason, so + // disabled for now... + // BOOST_STATIC_ASSERT(std::numeric_limits::digits == 106); + return 2.4651903288156618919116517665087e-32L; +} +#endif + +template +inline T epsilon(const mpl::false_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) +{ + BOOST_MATH_STD_USING // for ADL of std names + static const T eps = ldexp(static_cast(1), 1-policies::digits >()); + return eps; +} + +} // namespace detail + +template +inline T log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + typedef typename mpl::if_c< + std::numeric_limits::max_exponent == 128 + || std::numeric_limits::max_exponent == 1024 + || std::numeric_limits::max_exponent == 16384, + mpl::int_::max_exponent>, + mpl::int_<0> + >::type tag_type; + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); + return detail::log_max_value(tag_type()); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); + BOOST_MATH_STD_USING + static const T val = log((std::numeric_limits::max)()); + return val; +#endif +} + +template +inline T log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + typedef typename mpl::if_c< + std::numeric_limits::max_exponent == 128 + || std::numeric_limits::max_exponent == 1024 + || std::numeric_limits::max_exponent == 16384, + mpl::int_::max_exponent>, + mpl::int_<0> + >::type tag_type; + + BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized); + return detail::log_min_value(tag_type()); +#else + BOOST_ASSERT(::std::numeric_limits::is_specialized); + BOOST_MATH_STD_USING + static const T val = log((std::numeric_limits::min)()); + return val; +#endif +} + +template +inline T epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) +{ +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + return detail::epsilon(mpl::bool_< ::std::numeric_limits::is_specialized>()); +#else + return ::std::numeric_limits::is_specialized ? + detail::epsilon(mpl::true_()) : + detail::epsilon(mpl::false_()); +#endif +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_PRECISION_INCLUDED diff --git a/include/boost/math/tools/promotion.hpp b/include/boost/math/tools/promotion.hpp new file mode 100644 index 000000000..913574b31 --- /dev/null +++ b/include/boost/math/tools/promotion.hpp @@ -0,0 +1,120 @@ +// boost\math\tools\promotion.hpp + +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2006. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Promote arguments functions to allow math functions to have arguments +// provided as integer OR real (floating-point, built-in or UDT) +// (called ArithmeticType in functions that use promotion) +// that help to reduce the risk of creating multiple instantiations. +// Allows creation of an inline wrapper that forwards to a foo(RT, RT) function, +// so you never get to instantiate any mixed foo(RT, IT) functions. + +#ifndef BOOST_MATH_PROMOTION_HPP +#define BOOST_MATH_PROMOTION_HPP + +// Boost type traits: +#include +#include // for boost::is_floating_point; +#include // for boost::is_integral +#include // for boost::is_convertible +#include // for boost::is_same +#include // for boost::remove_cv +// Boost Template meta programming: +#include // for boost::mpl::if_c. +#include // for boost::mpl::if_c. +#include // for boost::mpl::if_c. + +#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +#include +#endif + +namespace boost +{ + namespace math + { + namespace tools + { + // If either T1 or T2 is an integer type, + // pretend it was a double (for the purposes of further analysis). + // Then pick the wider of the two floating-point types + // as the actual signature to forward to. + // For example: + // foo(int, short) -> double foo(double, double); + // foo(int, float) -> double foo(double, double); + // Note: NOT float foo(float, float) + // foo(int, double) -> foo(double, double); + // foo(double, float) -> double foo(double, double); + // foo(double, float) -> double foo(double, double); + // foo(any-int-or-float-type, long double) -> foo(long double, long double); + // but ONLY float foo(float, float) is unchanged. + // So the only way to get an entirely float version is to call foo(1.F, 2.F), + // But since most (all?) the math functions convert to double internally, + // probably there would not be the hoped-for gain by using float here. + + // This follows the C-compatible conversion rules of pow, etc + // where pow(int, float) is converted to pow(double, double). + + template + struct promote_arg + { // If T is integral type, then promote to double. + typedef typename mpl::if_, double, T>::type type; + }; + + template + struct promote_args_2 + { // Promote, if necessary, & pick the wider of the two floating-point types. + // for both parameter types, if integral promote to double. + typedef typename promote_arg::type T1P; // T1 perhaps promoted. + typedef typename promote_arg::type T2P; // T2 perhaps promoted. + + typedef typename mpl::if_< + typename mpl::and_, is_floating_point >::type, // both T1P and T2P are floating-point? + typename mpl::if_< typename mpl::or_, is_same >::type, // either long double? + long double, // then result type is long double. + typename mpl::if_< typename mpl::or_, is_same >::type, // either double? + double, // result type is double. + float // else result type is float. + >::type + >::type, + // else one or the other is a user-defined type: + typename mpl::if_< ::boost::is_convertible, T2P, T1P>::type>::type type; + }; // promote_arg2 + + template + struct promote_args + { + typedef typename promote_args_2< + typename remove_cv::type, + typename promote_args_2< + typename remove_cv::type, + typename promote_args_2< + typename remove_cv::type, + typename promote_args_2< + typename remove_cv::type, + typename promote_args_2< + typename remove_cv::type, typename remove_cv::type + >::type + >::type + >::type + >::type + >::type type; + +#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + // + // Guard against use of long double if it's not supported: + // + BOOST_STATIC_ASSERT((0 == ::boost::is_same::value)); +#endif + }; + + } // namespace tools + } // namespace math +} // namespace boost + +#endif // BOOST_MATH_PROMOTION_HPP diff --git a/include/boost/math/tools/rational.hpp b/include/boost/math/tools/rational.hpp new file mode 100644 index 000000000..81c348af5 --- /dev/null +++ b/include/boost/math/tools/rational.hpp @@ -0,0 +1,206 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_RATIONAL_HPP +#define BOOST_MATH_TOOLS_RATIONAL_HPP + +#include +#include +#include + +#if BOOST_MATH_POLY_METHOD == 1 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#elif BOOST_MATH_POLY_METHOD == 2 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#elif BOOST_MATH_POLY_METHOD == 3 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#endif +#if BOOST_MATH_RATIONAL_METHOD == 1 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#elif BOOST_MATH_RATIONAL_METHOD == 2 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#elif BOOST_MATH_RATIONAL_METHOD == 3 +# define BOOST_HEADER() +# include BOOST_HEADER() +# undef BOOST_HEADER +#endif +namespace boost{ namespace math{ namespace tools{ + +// +// Forward declaration to keep two phase lookup happy: +// +template +U evaluate_polynomial(const T* poly, U const& z, std::size_t count); + +namespace detail{ + +template +inline V evaluate_polynomial_c_imp(const T* a, const V& val, const Tag*) +{ + return evaluate_polynomial(a, val, Tag::value); +} + +} // namespace detail + +// +// Polynomial evaluation with runtime size. +// This requires a for-loop which may be more expensive than +// the loop expanded versions above: +// +template +inline U evaluate_polynomial(const T* poly, U const& z, std::size_t count) +{ + BOOST_ASSERT(count > 0); + U sum = static_cast(poly[count - 1]); + for(int i = static_cast(count) - 2; i >= 0; --i) + { + sum *= z; + sum += static_cast(poly[i]); + } + return sum; +} +// +// Compile time sized polynomials, just inline forwarders to the +// implementations above: +// +template +inline V evaluate_polynomial(const T(&a)[N], const V& val) +{ + typedef mpl::int_ tag_type; + return detail::evaluate_polynomial_c_imp(static_cast(a), val, static_cast(0)); +} + +template +inline V evaluate_polynomial(const boost::array& a, const V& val) +{ + typedef mpl::int_ tag_type; + return detail::evaluate_polynomial_c_imp(static_cast(a.data()), val, static_cast(0)); +} +// +// Even polynomials are trivial: just square the argument! +// +template +inline U evaluate_even_polynomial(const T* poly, U z, std::size_t count) +{ + return evaluate_polynomial(poly, z*z, count); +} + +template +inline V evaluate_even_polynomial(const T(&a)[N], const V& z) +{ + return evaluate_polynomial(a, z*z); +} + +template +inline V evaluate_even_polynomial(const boost::array& a, const V& z) +{ + return evaluate_polynomial(a, z*z); +} +// +// Odd polynomials come next: +// +template +inline U evaluate_odd_polynomial(const T* poly, U z, std::size_t count) +{ + return poly[0] + z * evaluate_polynomial(poly+1, z*z, count-1); +} + +template +inline V evaluate_odd_polynomial(const T(&a)[N], const V& z) +{ + typedef mpl::int_ tag_type; + return a[0] + z * detail::evaluate_polynomial_c_imp(static_cast(a) + 1, z*z, static_cast(0)); +} + +template +inline V evaluate_odd_polynomial(const boost::array& a, const V& z) +{ + typedef mpl::int_ tag_type; + return a[0] + z * detail::evaluate_polynomial_c_imp(static_cast(a.data()) + 1, z*z, static_cast(0)); +} + +template +V evaluate_rational(const T* num, const U* denom, const V& z_, std::size_t count); + +namespace detail{ + +template +inline V evaluate_rational_c_imp(const T* num, const U* denom, const V& z, const Tag*) +{ + return boost::math::tools::evaluate_rational(num, denom, z, Tag::value); +} + +} +// +// Rational functions: numerator and denominator must be +// equal in size. These always have a for-loop and so may be less +// efficient than evaluating a pair of polynomials. However, there +// are some tricks we can use to prevent overflow that might otherwise +// occur in polynomial evaluation, if z is large. This is important +// in our Lanczos code for example. +// +template +V evaluate_rational(const T* num, const U* denom, const V& z_, std::size_t count) +{ + V z(z_); + V s1, s2; + if(z <= 1) + { + s1 = static_cast(num[count-1]); + s2 = static_cast(denom[count-1]); + for(int i = (int)count - 2; i >= 0; --i) + { + s1 *= z; + s2 *= z; + s1 += num[i]; + s2 += denom[i]; + } + } + else + { + z = 1 / z; + s1 = static_cast(num[0]); + s2 = static_cast(denom[0]); + for(unsigned i = 1; i < count; ++i) + { + s1 *= z; + s2 *= z; + s1 += num[i]; + s2 += denom[i]; + } + } + return s1 / s2; +} + +template +inline V evaluate_rational(const T(&a)[N], const U(&b)[N], const V& z) +{ + return detail::evaluate_rational_c_imp(a, b, z, static_cast*>(0)); +} + +template +inline V evaluate_rational(const boost::array& a, const boost::array& b, const V& z) +{ + return detail::evaluate_rational_c_imp(a.data(), b.data(), z, static_cast*>(0)); +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_RATIONAL_HPP + + + diff --git a/include/boost/math/tools/real_cast.hpp b/include/boost/math/tools/real_cast.hpp new file mode 100644 index 000000000..7334cd460 --- /dev/null +++ b/include/boost/math/tools/real_cast.hpp @@ -0,0 +1,24 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_REAL_CAST_HPP +#define BOOST_MATH_TOOLS_REAL_CAST_HPP + +namespace boost{ namespace math +{ + namespace tools + { + template + inline To real_cast(T t) + { + return static_cast(t); + } + } // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_REAL_CAST_HPP + + diff --git a/include/boost/math/tools/remez.hpp b/include/boost/math/tools/remez.hpp new file mode 100644 index 000000000..e02183332 --- /dev/null +++ b/include/boost/math/tools/remez.hpp @@ -0,0 +1,662 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_REMEZ_HPP +#define BOOST_MATH_TOOLS_REMEZ_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +namespace detail{ + +// +// The error function: the difference between F(x) and +// the current approximation. This is the function +// for which we must find the extema. +// +template +struct remez_error_function +{ + typedef boost::function1 function_type; +public: + remez_error_function( + function_type f_, + const polynomial& n, + const polynomial& d, + bool rel_err) + : f(f_), numerator(n), denominator(d), rel_error(rel_err) {} + + T operator()(const T& z)const + { + T y = f(z); + T abs = y - (numerator.evaluate(z) / denominator.evaluate(z)); + T err; + if(rel_error) + { + if(y != 0) + err = abs / fabs(y); + else if(0 == abs) + { + // we must be at a root, or it's not recoverable: + BOOST_ASSERT(0 == abs); + err = 0; + } + else + { + // We have a divide by zero! + // Lets assume that f(x) is zero as a result of + // internal cancellation error that occurs as a result + // of shifting a root at point z to the origin so that + // the approximation can be "pinned" to pass through + // the origin: in that case it really + // won't matter what our approximation calculates here + // as long as it's a small number, return the absolute error: + err = abs; + } + } + else + err = abs; + return err; + } +private: + function_type f; + polynomial numerator; + polynomial denominator; + bool rel_error; +}; +// +// This function adapts the error function so that it's minima +// are the extema of the error function. We can find the minima +// with standard techniques. +// +template +struct remez_max_error_function +{ + remez_max_error_function(const remez_error_function& f) + : func(f) {} + + T operator()(const T& x) + { + BOOST_MATH_STD_USING + return -fabs(func(x)); + } +private: + remez_error_function func; +}; + +} // detail + +template +class remez_minimax +{ +public: + typedef boost::function1 function_type; + typedef boost::numeric::ublas::vector vector_type; + typedef boost::numeric::ublas::matrix matrix_type; + + remez_minimax(function_type f, unsigned oN, unsigned oD, T a, T b, bool pin = true, bool rel_err = false, int sk = 0, int bits = 0); + remez_minimax(function_type f, unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points); + + void reset(unsigned oN, unsigned oD, T a, T b, bool pin = true, bool rel_err = false, int sk = 0, int bits = 0); + void reset(unsigned oN, unsigned oD, T a, T b, bool pin, bool rel_err, int sk, int bits, const vector_type& points); + + void set_brake(int b) + { + BOOST_ASSERT(b < 100); + BOOST_ASSERT(b >= 0); + m_brake = b; + } + + T iterate(); + + polynomial denominator()const; + polynomial numerator()const; + + vector_type const& chebyshev_points()const + { + return control_points; + } + + vector_type const& zero_points()const + { + return zeros; + } + + T error_term()const + { + return solution[solution.size() - 1]; + } + T max_error()const + { + return m_max_error; + } + T max_change()const + { + return m_max_change; + } + void rotate() + { + --orderN; + ++orderD; + } + void rescale(T a, T b) + { + T scale = (b - a) / (max - min); + for(unsigned i = 0; i < control_points.size(); ++i) + { + control_points[i] = (control_points[i] - min) * scale + a; + } + min = a; + max = b; + } +private: + + void init_chebyshev(); + + function_type func; // The function to approximate. + vector_type control_points; // Current control points to be used for the next iteration. + vector_type solution; // Solution from the last iteration contains all unknowns including the error term. + vector_type zeros; // Location of points of zero error from last iteration, plus the two end points. + vector_type maxima; // Location of maxima of the error function, actually contains the control points used for the last iteration. + T m_max_error; // Maximum error found in last approximation. + T m_max_change; // Maximum change in location of control points after last iteration. + unsigned orderN; // Order of the numerator polynomial. + unsigned orderD; // Order of the denominator polynomial. + T min, max; // End points of the range to optimise over. + bool rel_error; // If true optimise for relative not absolute error. + bool pinned; // If true the approximation is "pinned" to go through the origin. + unsigned unknowns; // Total number of unknowns. + int m_precision; // Number of bits precision to which the zeros and maxima are found. + T m_max_change_history[2]; // Past history of changes to control points. + int m_brake; // amount to break by in percentage points. + int m_skew; // amount to skew starting points by in percentage points: -100-100 +}; + +#ifndef BRAKE +#define BRAKE 0 +#endif +#ifndef SKEW +#define SKEW 0 +#endif + +template +void remez_minimax::init_chebyshev() +{ + BOOST_MATH_STD_USING + // + // Fill in the zeros: + // + unsigned terms = pinned ? orderD + orderN : orderD + orderN + 1; + + for(unsigned i = 0; i < terms; ++i) + { + T cheb = cos((2 * terms - 1 - 2 * i) * constants::pi() / (2 * terms)); + cheb += 1; + cheb /= 2; + if(m_skew != 0) + { + T p = static_cast(200 + m_skew) / 200; + cheb = pow(cheb, p); + } + cheb *= (max - min); + cheb += min; + zeros[i+1] = cheb; + } + zeros[0] = min; + zeros[unknowns] = max; + // perform a regular interpolation fit: + matrix_type A(terms, terms); + vector_type b(terms); + // fill in the y values: + for(unsigned i = 0; i < b.size(); ++i) + { + b[i] = func(zeros[i+1]); + } + // fill in powers of x evaluated at each of the control points: + unsigned offsetN = pinned ? 0 : 1; + unsigned offsetD = offsetN + orderN; + unsigned maxorder = (std::max)(orderN, orderD); + for(unsigned i = 0; i < b.size(); ++i) + { + T x0 = zeros[i+1]; + T x = x0; + if(!pinned) + A(i, 0) = 1; + for(unsigned j = 0; j < maxorder; ++j) + { + if(j < orderN) + A(i, j + offsetN) = x; + if(j < orderD) + { + A(i, j + offsetD) = -x * b[i]; + } + x *= x0; + } + } + // + // Now go ahead and solve the expression to get our solution: + // + vector_type l_solution = boost::math::tools::solve(A, b); + // need to add a "fake" error term: + l_solution.resize(unknowns); + l_solution[unknowns-1] = 0; + solution = l_solution; + // + // Now find all the extrema of the error function: + // + detail::remez_error_function Err(func, this->numerator(), this->denominator(), rel_error); + detail::remez_max_error_function Ex(Err); + m_max_error = 0; + int max_err_location = 0; + for(unsigned i = 0; i < unknowns; ++i) + { + std::pair r = brent_find_minima(Ex, zeros[i], zeros[i+1], m_precision); + maxima[i] = r.first; + T rel_err = fabs(r.second); + if(rel_err > m_max_error) + { + m_max_error = fabs(r.second); + max_err_location = i; + } + } + control_points = maxima; +} + +template +void remez_minimax::reset( + unsigned oN, + unsigned oD, + T a, + T b, + bool pin, + bool rel_err, + int sk, + int bits) +{ + control_points = vector_type(oN + oD + (pin ? 1 : 2)); + solution = control_points; + zeros = vector_type(oN + oD + (pin ? 2 : 3)); + maxima = control_points; + orderN = oN; + orderD = oD; + rel_error = rel_err; + pinned = pin; + m_skew = sk; + min = a; + max = b; + m_max_error = 0; + unknowns = orderN + orderD + (pinned ? 1 : 2); + // guess our initial control points: + control_points[0] = min; + control_points[unknowns - 1] = max; + T interval = (max - min) / (unknowns - 1); + T spot = min + interval; + for(unsigned i = 1; i < control_points.size(); ++i) + { + control_points[i] = spot; + spot += interval; + } + solution[unknowns - 1] = 0; + m_max_error = 0; + if(bits == 0) + { + // don't bother about more than float precision: + m_precision = (std::min)(24, (boost::math::policies::digits >() / 2) - 2); + } + else + { + // can't be more accurate than half the bits of T: + m_precision = (std::min)(bits, (boost::math::policies::digits >() / 2) - 2); + } + m_max_change_history[0] = m_max_change_history[1] = 1; + init_chebyshev(); + // do one iteration whatever: + //iterate(); +} + +template +inline remez_minimax::remez_minimax( + typename remez_minimax::function_type f, + unsigned oN, + unsigned oD, + T a, + T b, + bool pin, + bool rel_err, + int sk, + int bits) + : func(f) +{ + m_brake = 0; + reset(oN, oD, a, b, pin, rel_err, sk, bits); +} + +template +void remez_minimax::reset( + unsigned oN, + unsigned oD, + T a, + T b, + bool pin, + bool rel_err, + int sk, + int bits, + const vector_type& points) +{ + control_points = vector_type(oN + oD + (pin ? 1 : 2)); + solution = control_points; + zeros = vector_type(oN + oD + (pin ? 2 : 3)); + maxima = control_points; + orderN = oN; + orderD = oD; + rel_error = rel_err; + pinned = pin; + m_skew = sk; + min = a; + max = b; + m_max_error = 0; + unknowns = orderN + orderD + (pinned ? 1 : 2); + control_points = points; + solution[unknowns - 1] = 0; + m_max_error = 0; + if(bits == 0) + { + // don't bother about more than float precision: + m_precision = (std::min)(24, (boost::math::policies::digits >() / 2) - 2); + } + else + { + // can't be more accurate than half the bits of T: + m_precision = (std::min)(bits, (boost::math::policies::digits >() / 2) - 2); + } + m_max_change_history[0] = m_max_change_history[1] = 1; + // do one iteration whatever: + //iterate(); +} + +template +inline remez_minimax::remez_minimax( + typename remez_minimax::function_type f, + unsigned oN, + unsigned oD, + T a, + T b, + bool pin, + bool rel_err, + int sk, + int bits, + const vector_type& points) + : func(f) +{ + m_brake = 0; + reset(oN, oD, a, b, pin, rel_err, sk, bits, points); +} + +template +T remez_minimax::iterate() +{ + BOOST_MATH_STD_USING + matrix_type A(unknowns, unknowns); + vector_type b(unknowns); + + // fill in evaluation of f(x) at each of the control points: + for(unsigned i = 0; i < b.size(); ++i) + { + // take care that none of our control points are at the origin: + if(pinned && (control_points[i] == 0)) + { + if(i) + control_points[i] = control_points[i-1] / 3; + else + control_points[i] = control_points[i+1] / 3; + } + b[i] = func(control_points[i]); + } + + T err_err; + unsigned convergence_count = 0; + do{ + // fill in powers of x evaluated at each of the control points: + int sign = 1; + unsigned offsetN = pinned ? 0 : 1; + unsigned offsetD = offsetN + orderN; + unsigned maxorder = (std::max)(orderN, orderD); + T Elast = solution[unknowns - 1]; + + for(unsigned i = 0; i < b.size(); ++i) + { + T x0 = control_points[i]; + T x = x0; + if(!pinned) + A(i, 0) = 1; + for(unsigned j = 0; j < maxorder; ++j) + { + if(j < orderN) + A(i, j + offsetN) = x; + if(j < orderD) + { + T mult = rel_error ? (b[i] - sign * fabs(b[i]) * Elast): (b[i] - sign * Elast); + A(i, j + offsetD) = -x * mult; + } + x *= x0; + } + // The last variable to be solved for is the error term, + // sign changes with each control point: + T E = rel_error ? sign * fabs(b[i]) : sign; + A(i, unknowns - 1) = E; + sign = -sign; + } + + #ifdef BOOST_MATH_INSTRUMENT + for(unsigned i = 0; i < b.size(); ++i) + std::cout << b[i] << " "; + std::cout << "\n\n"; + for(unsigned i = 0; i < b.size(); ++i) + { + for(unsigned j = 0; j < b.size(); ++ j) + std::cout << A(i, j) << " "; + std::cout << "\n"; + } + std::cout << std::endl; + #endif + // + // Now go ahead and solve the expression to get our solution: + // + solution = boost::math::tools::solve(A, b); + + err_err = (Elast != 0) ? fabs((fabs(solution[unknowns-1]) - fabs(Elast)) / fabs(Elast)) : 1; + }while(orderD && (convergence_count++ < 80) && (err_err > 0.001)); + + // + // Perform a sanity check to verify that the solution to the equations + // is not so much in error as to be useless. The matrix inversion can + // be very close to singular, so this can be a real problem. + // + vector_type sanity = prod(A, solution); + for(unsigned i = 0; i < b.size(); ++i) + { + T err = fabs((b[i] - sanity[i]) / fabs(b[i])); + if(err > sqrt(epsilon())) + { + std::cerr << "Sanity check failed: more than half the digits in the found solution are in error." << std::endl; + } + } + + // + // Next comes another sanity check, we want to verify that all the control + // points do actually alternate in sign, in practice we may have + // additional roots in the error function that cause this to fail. + // Failure here is always fatal: even though this code attempts to correct + // the problem it usually only postpones the inevitable. + // + polynomial num, denom; + num = this->numerator(); + denom = this->denominator(); + T e1 = b[0] - num.evaluate(control_points[0]) / denom.evaluate(control_points[0]); +#ifdef BOOST_MATH_INSTRUMENT + std::cout << e1; +#endif + for(unsigned i = 1; i < b.size(); ++i) + { + T e2 = b[i] - num.evaluate(control_points[i]) / denom.evaluate(control_points[i]); +#ifdef BOOST_MATH_INSTRUMENT + std::cout << " " << e2; +#endif + if(e2 * e1 > 0) + { + std::cerr << std::flush << "Basic sanity check failed: Error term does not alternate in sign, non-recoverable error may follow..." << std::endl; + T perturbation = 0.05; + do{ + T point = control_points[i] * (1 - perturbation) + control_points[i-1] * perturbation; + e2 = func(point) - num.evaluate(point) / denom.evaluate(point); + if(e2 * e1 < 0) + { + control_points[i] = point; + break; + } + perturbation += 0.05; + }while(perturbation < 0.8); + + if((e2 * e1 > 0) && (i + 1 < b.size())) + { + perturbation = 0.05; + do{ + T point = control_points[i] * (1 - perturbation) + control_points[i+1] * perturbation; + e2 = func(point) - num.evaluate(point) / denom.evaluate(point); + if(e2 * e1 < 0) + { + control_points[i] = point; + break; + } + perturbation += 0.05; + }while(perturbation < 0.8); + } + + } + e1 = e2; + } + +#ifdef BOOST_MATH_INSTRUMENT + for(unsigned i = 0; i < solution.size(); ++i) + std::cout << solution[i] << " "; + std::cout << std::endl << this->numerator() << std::endl; + std::cout << this->denominator() << std::endl; + std::cout << std::endl; +#endif + + // + // The next step is to find all the intervals in which our maxima + // lie: + // + detail::remez_error_function Err(func, this->numerator(), this->denominator(), rel_error); + zeros[0] = min; + zeros[unknowns] = max; + for(unsigned i = 1; i < control_points.size(); ++i) + { + eps_tolerance tol(m_precision); + boost::uintmax_t max_iter = 1000; + std::pair p = toms748_solve( + Err, + control_points[i-1], + control_points[i], + tol, + max_iter); + zeros[i] = (p.first + p.second) / 2; + //zeros[i] = bisect(Err, control_points[i-1], control_points[i], m_precision); + } + // + // Now find all the extrema of the error function: + // + detail::remez_max_error_function Ex(Err); + m_max_error = 0; + int max_err_location = 0; + for(unsigned i = 0; i < unknowns; ++i) + { + std::pair r = brent_find_minima(Ex, zeros[i], zeros[i+1], m_precision); + maxima[i] = r.first; + T rel_err = fabs(r.second); + if(rel_err > m_max_error) + { + m_max_error = fabs(r.second); + max_err_location = i; + } + } + // + // Almost done now! we just need to set our control points + // to the extrema, and calculate how much each point has changed + // (this will be our termination condition): + // + swap(control_points, maxima); + m_max_change = 0; + int max_change_location = 0; + for(unsigned i = 0; i < unknowns; ++i) + { + control_points[i] = (control_points[i] * (100 - m_brake) + maxima[i] * m_brake) / 100; + T change = fabs((control_points[i] - maxima[i]) / control_points[i]); +#if 0 + if(change > m_max_change_history[1]) + { + // divergence!!! try capping the change: + std::cerr << "Possible divergent step, change will be capped!!" << std::endl; + change = m_max_change_history[1]; + if(control_points[i] < maxima[i]) + control_points[i] = maxima[i] - change * maxima[i]; + else + control_points[i] = maxima[i] + change * maxima[i]; + } +#endif + if(change > m_max_change) + { + m_max_change = change; + max_change_location = i; + } + } + // + // store max change information: + // + m_max_change_history[0] = m_max_change_history[1]; + m_max_change_history[1] = fabs(m_max_change); + + return m_max_change; +} + +template +polynomial remez_minimax::numerator()const +{ + boost::scoped_array a(new T[orderN + 1]); + if(pinned) + a[0] = 0; + unsigned terms = pinned ? orderN : orderN + 1; + for(unsigned i = 0; i < terms; ++i) + a[pinned ? i+1 : i] = solution[i]; + return boost::math::tools::polynomial(&a[0], orderN); +} + +template +polynomial remez_minimax::denominator()const +{ + unsigned terms = orderD + 1; + unsigned offsetD = pinned ? orderN : (orderN + 1); + boost::scoped_array a(new T[terms]); + a[0] = 1; + for(unsigned i = 0; i < orderD; ++i) + a[i+1] = solution[i + offsetD]; + return boost::math::tools::polynomial(&a[0], orderD); +} + + +}}} // namespaces + +#endif // BOOST_MATH_TOOLS_REMEZ_HPP + + diff --git a/include/boost/math/tools/roots.hpp b/include/boost/math/tools/roots.hpp new file mode 100644 index 000000000..6412fe9f2 --- /dev/null +++ b/include/boost/math/tools/roots.hpp @@ -0,0 +1,522 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP +#define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4512) +#endif +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +namespace detail{ + +template +inline void unpack_0(const Tuple& t, T& val) +{ val = std::tr1::get<0>(t); } + +template +void handle_zero_derivative(F f, + T& last_f0, + const T& f0, + T& delta, + T& result, + T& guess, + const T& min, + const T& max) +{ + if(last_f0 == 0) + { + // this must be the first iteration, pretend that we had a + // previous one at either min or max: + if(result == min) + { + guess = max; + } + else + { + guess = min; + } + unpack_0(f(guess), last_f0); + //last_f0 = std::tr1::get<0>(f(guess)); + delta = guess - result; + } + if(sign(last_f0) * sign(f0) < 0) + { + // we've crossed over so move in opposite direction to last step: + if(delta < 0) + { + delta = (result - min) / 2; + } + else + { + delta = (result - max) / 2; + } + } + else + { + // move in same direction as last step: + if(delta < 0) + { + delta = (result - max) / 2; + } + else + { + delta = (result - min) / 2; + } + } +} + +} // namespace + +template +std::pair bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) +{ + T fmin = f(min); + T fmax = f(max); + if(fmin == 0) + return std::make_pair(min, min); + if(fmax == 0) + return std::make_pair(max, max); + + // + // Error checking: + // + static const char* function = "boost::math::tools::bisect<%1%>"; + if(min >= max) + { + policies::raise_evaluation_error(function, + "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol); + } + if(fmin * fmax >= 0) + { + policies::raise_evaluation_error(function, + "No change of sign in boost::math::tools::bisect, either there is no root to find, or there are multiple roots in the interval (f(min) = %1%).", fmin, pol); + } + + // + // Three function invocations so far: + // + boost::uintmax_t count = max_iter; + if(count < 3) + count = 0; + else + count -= 3; + + while(count && (0 == tol(min, max))) + { + T mid = (min + max) / 2; + T fmid = f(mid); + if((mid == max) || (mid == min)) + break; + if(fmid == 0) + { + min = max = mid; + break; + } + else if(sign(fmid) * sign(fmin) < 0) + { + max = mid; + fmax = fmid; + } + else + { + min = mid; + fmin = fmid; + } + --count; + } + + max_iter -= count; + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Bisection iteration, final count = " << max_iter << std::endl; + + static boost::uintmax_t max_count = 0; + if(max_iter > max_count) + { + max_count = max_iter; + std::cout << "Maximum iterations: " << max_iter << std::endl; + } +#endif + + return std::make_pair(min, max); +} + +template +inline std::pair bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter) +{ + return bisect(f, min, max, tol, max_iter, policies::policy<>()); +} + +template +inline std::pair bisect(F f, T min, T max, Tol tol) +{ + boost::uintmax_t m = (std::numeric_limits::max)(); + return bisect(f, min, max, tol, m, policies::policy<>()); +} + +template +T newton_raphson_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) +{ + BOOST_MATH_STD_USING + + T f0(0), f1, last_f0(0); + T result = guess; + + T factor = static_cast(ldexp(1.0, 1 - digits)); + T delta = 1; + T delta1 = tools::max_value(); + T delta2 = tools::max_value(); + + boost::uintmax_t count(max_iter); + + do{ + last_f0 = f0; + delta2 = delta1; + delta1 = delta; + std::tr1::tie(f0, f1) = f(result); + if(0 == f0) + break; + if(f1 == 0) + { + // Oops zero derivative!!! +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Newton iteration, zero derivative found" << std::endl; +#endif + detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max); + } + else + { + delta = f0 / f1; + } +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Newton iteration, delta = " << delta << std::endl; +#endif + if(fabs(delta * 2) > fabs(delta2)) + { + // last two steps haven't converged, try bisection: + delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2; + } + guess = result; + result -= delta; + if(result <= min) + { + delta = 0.5F * (guess - min); + result = guess - delta; + if((result == min) || (result == max)) + break; + } + else if(result >= max) + { + delta = 0.5F * (guess - max); + result = guess - delta; + if((result == min) || (result == max)) + break; + } + // update brackets: + if(delta > 0) + max = guess; + else + min = guess; + }while(--count && (fabs(result * factor) < fabs(delta))); + + max_iter -= count; + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Newton Raphson iteration, final count = " << max_iter << std::endl; + + static boost::uintmax_t max_count = 0; + if(max_iter > max_count) + { + max_count = max_iter; + std::cout << "Maximum iterations: " << max_iter << std::endl; + } +#endif + + return result; +} + +template +inline T newton_raphson_iterate(F f, T guess, T min, T max, int digits) +{ + boost::uintmax_t m = (std::numeric_limits::max)(); + return newton_raphson_iterate(f, guess, min, max, digits, m); +} + +template +T halley_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) +{ + BOOST_MATH_STD_USING + + T f0(0), f1, f2; + T result = guess; + + T factor = static_cast(ldexp(1.0, 1 - digits)); + T delta = (std::max)(10000000 * guess, T(10000000)); // arbitarily large delta + T last_f0 = 0; + T delta1 = delta; + T delta2 = delta; + + bool out_of_bounds_sentry = false; + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, limit = " << factor << std::endl; +#endif + + boost::uintmax_t count(max_iter); + + do{ + last_f0 = f0; + delta2 = delta1; + delta1 = delta; + std::tr1::tie(f0, f1, f2) = f(result); + if(0 == f0) + break; + if((f1 == 0) && (f2 == 0)) + { + // Oops zero derivative!!! +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, zero derivative found" << std::endl; +#endif + detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max); + } + else + { + if(f2 != 0) + { + T denom = 2 * f0; + T num = 2 * f1 - f0 * (f2 / f1); + if((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value())) + { + // possible overflow, use Newton step: + delta = f0 / f1; + } + else + delta = denom / num; + if(delta * f1 / f0 < 0) + { + // probably cancellation error, try a Newton step instead: + delta = f0 / f1; + } + } + else + delta = f0 / f1; + } +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, delta = " << delta << std::endl; +#endif + T convergence = fabs(delta / delta2); + if((convergence > 0.8) && (convergence < 2)) + { + // last two steps haven't converged, try bisection: + delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2; + // reset delta2 so that this branch will *not* be taken on the + // next iteration: + delta2 = delta * 3; + } + guess = result; + result -= delta; + + // check for out of bounds step: + if(result < min) + { + T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value() / fabs(result) < fabs(min))) ? 1000 : result / min; + if(fabs(diff) < 1) + diff = 1 / diff; + if(!out_of_bounds_sentry && (diff > 0) && (diff < 3)) + { + // Only a small out of bounds step, lets assume that the result + // is probably approximately at min: + delta = 0.99f * (guess - min); + result = guess - delta; + out_of_bounds_sentry = true; // only take this branch once! + } + else + { + delta = (guess - min) / 2; + result = guess - delta; + if((result == min) || (result == max)) + break; + } + } + else if(result > max) + { + T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value() / fabs(result) < fabs(max))) ? 1000 : result / max; + if(fabs(diff) < 1) + diff = 1 / diff; + if(!out_of_bounds_sentry && (diff > 0) && (diff < 3)) + { + // Only a small out of bounds step, lets assume that the result + // is probably approximately at min: + delta = 0.99f * (guess - max); + result = guess - delta; + out_of_bounds_sentry = true; // only take this branch once! + } + else + { + delta = (guess - max) / 2; + result = guess - delta; + if((result == min) || (result == max)) + break; + } + } + // update brackets: + if(delta > 0) + max = guess; + else + min = guess; + }while(--count && (fabs(result * factor) < fabs(delta))); + + max_iter -= count; + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, final count = " << max_iter << std::endl; + + static boost::uintmax_t max_count = 0; + if(max_iter > max_count) + { + max_count = max_iter; + std::cout << "Maximum iterations: " << max_iter << std::endl; + } +#endif + + return result; +} + +template +inline T halley_iterate(F f, T guess, T min, T max, int digits) +{ + boost::uintmax_t m = (std::numeric_limits::max)(); + return halley_iterate(f, guess, min, max, digits, m); +} + +template +T schroeder_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) +{ + BOOST_MATH_STD_USING + + T f0(0), f1, f2, last_f0(0); + T result = guess; + + T factor = static_cast(ldexp(1.0, 1 - digits)); + T delta = 0; + T delta1 = tools::max_value(); + T delta2 = tools::max_value(); + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Schroeder iteration, limit = " << factor << std::endl; +#endif + + boost::uintmax_t count(max_iter); + + do{ + last_f0 = f0; + delta2 = delta1; + delta1 = delta; + std::tr1::tie(f0, f1, f2) = f(result); + if(0 == f0) + break; + if((f1 == 0) && (f2 == 0)) + { + // Oops zero derivative!!! +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, zero derivative found" << std::endl; +#endif + detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max); + } + else + { + T ratio = f0 / f1; + if(ratio / result < 0.1) + { + delta = ratio + (f2 / (2 * f1)) * ratio * ratio; + // check second derivative doesn't over compensate: + if(delta * ratio < 0) + delta = ratio; + } + else + delta = ratio; // fall back to Newton iteration. + } + if(fabs(delta * 2) > fabs(delta2)) + { + // last two steps haven't converged, try bisection: + delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2; + } + guess = result; + result -= delta; +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Halley iteration, delta = " << delta << std::endl; +#endif + if(result <= min) + { + delta = 0.5F * (guess - min); + result = guess - delta; + if((result == min) || (result == max)) + break; + } + else if(result >= max) + { + delta = 0.5F * (guess - max); + result = guess - delta; + if((result == min) || (result == max)) + break; + } + // update brackets: + if(delta > 0) + max = guess; + else + min = guess; + }while(--count && (fabs(result * factor) < fabs(delta))); + + max_iter -= count; + +#ifdef BOOST_MATH_INSTRUMENT + std::cout << "Schroeder iteration, final count = " << max_iter << std::endl; + + static boost::uintmax_t max_count = 0; + if(max_iter > max_count) + { + max_count = max_iter; + std::cout << "Maximum iterations: " << max_iter << std::endl; + } +#endif + + return result; +} + +template +inline T schroeder_iterate(F f, T guess, T min, T max, int digits) +{ + boost::uintmax_t m = (std::numeric_limits::max)(); + return schroeder_iterate(f, guess, min, max, digits, m); +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP + + diff --git a/include/boost/math/tools/series.hpp b/include/boost/math/tools/series.hpp new file mode 100644 index 000000000..94f264de8 --- /dev/null +++ b/include/boost/math/tools/series.hpp @@ -0,0 +1,171 @@ +// (C) Copyright John Maddock 2005-2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_SERIES_INCLUDED +#define BOOST_MATH_TOOLS_SERIES_INCLUDED + +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +// +// Simple series summation come first: +// +template +typename Functor::result_type sum_series(Functor& func, int bits) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + result_type factor = pow(result_type(2), bits); + result_type result = func(); + result_type next_term; + do{ + next_term = func(); + result += next_term; + } + while(fabs(result) < fabs(factor * next_term)); + return result; +} + +template +typename Functor::result_type sum_series(Functor& func, int bits, boost::uintmax_t& max_terms) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + boost::uintmax_t counter = max_terms; + + result_type factor = ldexp(result_type(1), bits); + result_type result = func(); + result_type next_term; + do{ + next_term = func(); + result += next_term; + } + while((fabs(result) < fabs(factor * next_term)) && --counter); + + // set max_terms to the actual number of terms of the series evaluated: + max_terms = max_terms - counter; + + return result; +} + +template +typename Functor::result_type sum_series(Functor& func, int bits, U init_value) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + result_type factor = ldexp(result_type(1), bits); + result_type result = static_cast(init_value); + result_type next_term; + do{ + next_term = func(); + result += next_term; + } + while(fabs(result) < fabs(factor * next_term)); + + return result; +} + +template +typename Functor::result_type sum_series(Functor& func, int bits, boost::uintmax_t& max_terms, U init_value) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + boost::uintmax_t counter = max_terms; + + result_type factor = ldexp(result_type(1), bits); + result_type result = init_value; + result_type next_term; + do{ + next_term = func(); + result += next_term; + } + while((fabs(result) < fabs(factor * next_term)) && --counter); + + // set max_terms to the actual number of terms of the series evaluated: + max_terms = max_terms - counter; + + return result; +} + +// +// Algorithm kahan_sum_series invokes Functor func until the N'th +// term is too small to have any effect on the total, the terms +// are added using the Kahan summation method. +// +// CAUTION: Optimizing compilers combined with extended-precision +// machine registers conspire to render this algorithm partly broken: +// double rounding of intermediate terms (first to a long double machine +// register, and then to a double result) cause the rounding error computed +// by the algorithm to be off by up to 1ulp. However this occurs rarely, and +// in any case the result is still much better than a naive summation. +// +template +typename Functor::result_type kahan_sum_series(Functor& func, int bits) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + result_type factor = pow(result_type(2), bits); + result_type result = func(); + result_type next_term, y, t; + result_type carry = 0; + do{ + next_term = func(); + y = next_term - carry; + t = result + y; + carry = t - result; + carry -= y; + result = t; + } + while(fabs(result) < fabs(factor * next_term)); + return result; +} + +template +typename Functor::result_type kahan_sum_series(Functor& func, int bits, boost::uintmax_t& max_terms) +{ + BOOST_MATH_STD_USING + + typedef typename Functor::result_type result_type; + + boost::uintmax_t counter = max_terms; + + result_type factor = ldexp(result_type(1), bits); + result_type result = func(); + result_type next_term, y, t; + result_type carry = 0; + do{ + next_term = func(); + y = next_term - carry; + t = result + y; + carry = t - result; + carry -= y; + result = t; + } + while((fabs(result) < fabs(factor * next_term)) && --counter); + + // set max_terms to the actual number of terms of the series evaluated: + max_terms = max_terms - counter; + + return result; +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif // BOOST_MATH_TOOLS_SERIES_INCLUDED diff --git a/include/boost/math/tools/solve.hpp b/include/boost/math/tools/solve.hpp new file mode 100644 index 000000000..9683ad561 --- /dev/null +++ b/include/boost/math/tools/solve.hpp @@ -0,0 +1,74 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_SOLVE_HPP +#define BOOST_MATH_TOOLS_SOLVE_HPP + +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996 4267 4244) +#endif + +#include +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ namespace math{ namespace tools{ + +// +// Find x such that Ax = b +// +// Caution: this uses undocumented, and untested ublas code, +// however short of writing our own LU-decompostion code +// it's the only game in town. +// +template +boost::numeric::ublas::vector solve( + const boost::numeric::ublas::matrix& A_, + const boost::numeric::ublas::vector& b_) +{ + //BOOST_ASSERT(A_.size() == b_.size()); + + boost::numeric::ublas::matrix A(A_); + boost::numeric::ublas::vector b(b_); + boost::numeric::ublas::permutation_matrix<> piv(b.size()); + lu_factorize(A, piv); + lu_substitute(A, piv, b); + // + // iterate to reduce error: + // + boost::numeric::ublas::vector delta(b.size()); + for(unsigned i = 0; i < 1; ++i) + { + noalias(delta) = prod(A_, b); + delta -= b_; + lu_substitute(A, piv, delta); + b -= delta; + + T max_error = 0; + + for(unsigned i = 0; i < delta.size(); ++i) + { + T err = fabs(delta[i] / b[i]); + if(err > max_error) + max_error = err; + } + //std::cout << "Max change in LU error correction: " << max_error << std::endl; + } + + return b; +} + +}}} // namespaces + +#endif // BOOST_MATH_TOOLS_SOLVE_HPP + diff --git a/include/boost/math/tools/stats.hpp b/include/boost/math/tools/stats.hpp new file mode 100644 index 000000000..e9e55456f --- /dev/null +++ b/include/boost/math/tools/stats.hpp @@ -0,0 +1,83 @@ +// (C) Copyright John Maddock 2005-2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_STATS_INCLUDED +#define BOOST_MATH_TOOLS_STATS_INCLUDED + +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +template +class stats +{ +public: + stats() + : m_min(tools::max_value()), + m_max(-tools::max_value()), + m_total(0), + m_squared_total(0), + m_count(0) + {} + void add(const T& val) + { + if(val < m_min) + m_min = val; + if(val > m_max) + m_max = val; + m_total += val; + ++m_count; + m_squared_total += val*val; + } + T min BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return m_min; } + T max BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return m_max; } + T total()const{ return m_total; } + T mean()const{ return m_total / static_cast(m_count); } + boost::uintmax_t count()const{ return m_count; } + T variance()const + { + BOOST_MATH_STD_USING + + T t = m_squared_total - m_total * m_total / m_count; + t /= m_count; + return t; + } + T variance1()const + { + BOOST_MATH_STD_USING + + T t = m_squared_total - m_total * m_total / m_count; + t /= (m_count-1); + return t; + } + T rms()const + { + BOOST_MATH_STD_USING + + return sqrt(m_squared_total / static_cast(m_count)); + } + stats& operator+=(const stats& s) + { + if(s.m_min < m_min) + m_min = s.m_min; + if(s.m_max > m_max) + m_max = s.m_max; + m_total += s.m_total; + m_squared_total += s.m_squared_total; + m_count += s.m_count; + return *this; + } +private: + T m_min, m_max, m_total, m_squared_total; + boost::uintmax_t m_count; +}; + +} // namespace tools +} // namespace math +} // namespace boost + +#endif diff --git a/include/boost/math/tools/test.hpp b/include/boost/math/tools/test.hpp new file mode 100644 index 000000000..3000e0818 --- /dev/null +++ b/include/boost/math/tools/test.hpp @@ -0,0 +1,242 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_TEST_HPP +#define BOOST_MATH_TOOLS_TEST_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +template +struct test_result +{ +private: + boost::math::tools::stats stat; // Statistics for the test. + unsigned worst_case; // Index of the worst case test. +public: + test_result() { worst_case = 0; } + void set_worst(int i){ worst_case = i; } + void add(const T& point){ stat.add(point); } + // accessors: + unsigned worst()const{ return worst_case; } + T min BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.min)(); } + T max BOOST_PREVENT_MACRO_SUBSTITUTION()const{ return (stat.max)(); } + T total()const{ return stat.total(); } + T mean()const{ return stat.mean(); } + boost::uintmax_t count()const{ return stat.count(); } + T variance()const{ return stat.variance(); } + T variance1()const{ return stat.variance1(); } + T rms()const{ return stat.rms(); } + + test_result& operator+=(const test_result& t) + { + if((t.stat.max)() > (stat.max)()) + worst_case = t.worst_case; + stat += t.stat; + return *this; + } +}; + +template +struct calculate_result_type +{ + typedef typename T::value_type row_type; + typedef typename row_type::value_type value_type; +}; + +template +T relative_error(T a, T b) +{ + BOOST_MATH_STD_USING +#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + // + // If math.h has no long double support we can't rely + // on the math functions generating exponents outside + // the range of a double: + // + T min_val = (std::max)( + tools::min_value(), + static_cast((std::numeric_limits::min)())); + T max_val = (std::min)( + tools::max_value(), + static_cast((std::numeric_limits::max)())); +#else + T min_val = tools::min_value(); + T max_val = tools::max_value(); +#endif + + if((a != 0) && (b != 0)) + { + // TODO: use isfinite: + if(fabs(b) >= max_val) + { + if(fabs(a) >= max_val) + return 0; // one infinity is as good as another! + } + // If the result is denormalised, treat all denorms as equivalent: + if((a < min_val) && (a > 0)) + a = min_val; + else if((a > -min_val) && (a < 0)) + a = -min_val; + if((b < min_val) && (b > 0)) + b = min_val; + else if((b > -min_val) && (b < 0)) + b = -min_val; + return (std::max)(fabs((a-b)/a), fabs((a-b)/b)); + } + + // Handle special case where one or both are zero: + if(min_val == 0) + return fabs(a-b); + if(fabs(a) < min_val) + a = min_val; + if(fabs(b) < min_val) + b = min_val; + return (std::max)(fabs((a-b)/a), fabs((a-b)/b)); +} + +#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +template <> +inline double relative_error(double a, double b) +{ + BOOST_MATH_STD_USING + // + // On Mac OS X we evaluate "double" functions at "long double" precision, + // but "long double" actually has a very slightly narrower range than "double"! + // Therefore use the range of "long double" as our limits since results outside + // that range may have been truncated to 0 or INF: + // + double min_val = (std::max)((double)tools::min_value(), tools::min_value()); + double max_val = (std::min)((double)tools::max_value(), tools::max_value()); + + if((a != 0) && (b != 0)) + { + // TODO: use isfinite: + if(b > max_val) + { + if(a > max_val) + return 0; // one infinity is as good as another! + } + // If the result is denormalised, treat all denorms as equivalent: + if((a < min_val) && (a > 0)) + a = min_val; + else if((a > -min_val) && (a < 0)) + a = -min_val; + if((b < min_val) && (b > 0)) + b = min_val; + else if((b > -min_val) && (b < 0)) + b = -min_val; + return (std::max)(fabs((a-b)/a), fabs((a-b)/b)); + } + + // Handle special case where one or both are zero: + if(min_val == 0) + return fabs(a-b); + if(fabs(a) < min_val) + a = min_val; + if(fabs(b) < min_val) + b = min_val; + return (std::max)(fabs((a-b)/a), fabs((a-b)/b)); +} +#endif + +template +void print_row(const Seq& row) +{ + for(unsigned i = 0; i < row.size(); ++i) + { + if(i) + std::cout << ", "; + std::cout << row[i]; + } + std::cout << std::endl; +} + +// +// Function test accepts an matrix of input values (probably a 2D boost::array) +// and calls two functors for each row in the array - one calculates a value +// to test, and one extracts the expected value from the array (or possibly +// calculates it at high precision). The two functors are usually simple lambda +// expressions. +// +template +test_result::value_type> test(const A& a, F1 test_func, F2 expect_func) +{ + typedef typename A::value_type row_type; + typedef typename row_type::value_type value_type; + + test_result result; + + for(unsigned i = 0; i < a.size(); ++i) + { + const row_type& row = a[i]; + value_type point; + try + { + point = test_func(row); + } + catch(const std::underflow_error&) + { + point = 0; + } + catch(const std::overflow_error&) + { + point = std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() + : tools::max_value(); + } + catch(const std::exception& e) + { + std::cerr << e.what() << std::endl; + print_row(row); + BOOST_ERROR("Unexpected exception."); + // so we don't get further errors: + point = expect_func(row); + } + value_type expected = expect_func(row); + value_type err = relative_error(point, expected); +#ifdef BOOST_INSTRUMENT + if(err != 0) + { + std::cout << row[0] << " " << err; + if(std::numeric_limits::is_specialized) + { + std::cout << " (" << err / std::numeric_limits::epsilon() << "eps)"; + } + std::cout << std::endl; + } +#endif + if(!(boost::math::isfinite)(point) && (boost::math::isfinite)(expected)) + { + std::cout << "CAUTION: Found non-finite result, when a finite value was expected at entry " << i << "\n"; + std::cout << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl; + print_row(row); + BOOST_ERROR("Unexpected non-finite result"); + } + if(err > 0.5) + { + std::cout << "CAUTION: Gross error found at entry " << i << ".\n"; + std::cout << "Found: " << point << " Expected " << expected << " Error: " << err << std::endl; + print_row(row); + BOOST_ERROR("Gross error"); + } + result.add(err); + if((result.max)() == err) + result.set_worst(i); + } + return result; +} + +} // namespace tools +} // namespace math +} // namespace boost + +#endif + diff --git a/include/boost/math/tools/test_data.hpp b/include/boost/math/tools/test_data.hpp new file mode 100644 index 000000000..f74b65af5 --- /dev/null +++ b/include/boost/math/tools/test_data.hpp @@ -0,0 +1,755 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_TEST_DATA_HPP +#define BOOST_MATH_TOOLS_TEST_DATA_HPP + +#include +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127 4701 4512) +# pragma warning(disable: 4130) // '==' : logical operation on address of string constant. +#endif +#include +#include +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4130) // '==' : logical operation on address of string constant. +// Used as a warning with BOOST_ASSERT +#endif + +namespace boost{ namespace math{ namespace tools{ + +enum parameter_type +{ + random_in_range = 0, + periodic_in_range = 1, + power_series = 2, + dummy_param = 0x80 +}; + +parameter_type operator | (parameter_type a, parameter_type b) +{ + return static_cast((int)a|(int)b); +} +parameter_type& operator |= (parameter_type& a, parameter_type b) +{ + a = static_cast(a|b); + return a; +} + +// +// If type == random_in_range then +// z1 and r2 are the endpoints of the half open range and n1 is the number of points. +// +// If type == periodic_in_range then +// z1 and r2 are the endpoints of the half open range and n1 is the number of points. +// +// If type == power_series then +// n1 and n2 are the endpoints of the exponents (closed range) and z1 is the basis. +// +// If type & dummy_param then this data is ignored and not stored in the output, it +// is passed to the generator function however which can do with it as it sees fit. +// +template +struct parameter_info +{ + parameter_type type; + T z1, z2; + int n1, n2; +}; + +template +inline parameter_info make_random_param(T start_range, T end_range, int n_points) +{ + parameter_info result = { random_in_range, start_range, end_range, n_points, 0 }; + return result; +} + +template +inline parameter_info make_periodic_param(T start_range, T end_range, int n_points) +{ + parameter_info result = { periodic_in_range, start_range, end_range, n_points, 0 }; + return result; +} + +template +inline parameter_info make_power_param(T basis, int start_exponent, int end_exponent) +{ + parameter_info result = { power_series, basis, 0, start_exponent, end_exponent }; + return result; +} + +namespace detail{ + +template +inline void unpack_and_append_tuple(Seq& s, + const Item& data, + const boost::integral_constant&, + const boost::false_type&) +{ + // termimation condition nothing to do here +} + +template +inline void unpack_and_append_tuple(Seq& s, + const Item& data, + const boost::integral_constant&, + const boost::true_type&) +{ + // extract the N'th element, append, and recurse: + typedef typename Seq::value_type value_type; + value_type val = std::tr1::get(data); + s.push_back(val); + + typedef boost::integral_constant next_value; + typedef boost::integral_constant::value > N+1)> terminate; + + unpack_and_append_tuple(s, data, next_value(), terminate()); +} + +template +inline void unpack_and_append(Seq& s, const Item& data, const boost::true_type&) +{ + s.push_back(data); +} + +template +inline void unpack_and_append(Seq& s, const Item& data, const boost::false_type&) +{ + // Item had better be a tuple-like type or we've had it!!!! + typedef boost::integral_constant next_value; + typedef boost::integral_constant::value > 0)> terminate; + + unpack_and_append_tuple(s, data, next_value(), terminate()); +} + +template +inline void unpack_and_append(Seq& s, const Item& data) +{ + typedef typename Seq::value_type value_type; + unpack_and_append(s, data, ::boost::is_convertible()); +} + +} // detail + +template +class test_data +{ +public: + typedef std::vector row_type; + typedef row_type value_type; +private: + typedef std::set container_type; +public: + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::size_type size_type; + + // creation: + test_data(){} + template + test_data(F func, const parameter_info& arg1) + { + insert(func, arg1); + } + + // insertion: + template + test_data& insert(F func, const parameter_info& arg1) + { + // generate data for single argument functor F + + typedef typename std::set::const_iterator it_type; + + std::set points; + create_test_points(points, arg1); + it_type a = points.begin(); + it_type b = points.end(); + row_type row; + while(a != b) + { + if((arg1.type & dummy_param) == 0) + row.push_back(*a); + try{ + // domain_error exceptions from func are swallowed + // and this data point is ignored: + boost::math::tools::detail::unpack_and_append(row, func(*a)); + m_data.insert(row); + } + catch(const std::domain_error&){} + row.clear(); + ++a; + } + return *this; + } + + template + test_data& insert(F func, const parameter_info& arg1, const parameter_info& arg2) + { + // generate data for 2-argument functor F + + typedef typename std::set::const_iterator it_type; + + std::set points1, points2; + create_test_points(points1, arg1); + create_test_points(points2, arg2); + it_type a = points1.begin(); + it_type b = points1.end(); + row_type row; + while(a != b) + { + it_type c = points2.begin(); + it_type d = points2.end(); + while(c != d) + { + if((arg1.type & dummy_param) == 0) + row.push_back(*a); + if((arg2.type & dummy_param) == 0) + row.push_back(*c); + try{ + // domain_error exceptions from func are swallowed + // and this data point is ignored: + detail::unpack_and_append(row, func(*a, *c)); + m_data.insert(row); + } + catch(const std::domain_error&){} + row.clear(); + ++c; + } + ++a; + } + return *this; + } + + template + test_data& insert(F func, const parameter_info& arg1, const parameter_info& arg2, const parameter_info& arg3) + { + // generate data for 3-argument functor F + + typedef typename std::set::const_iterator it_type; + + std::set points1, points2, points3; + create_test_points(points1, arg1); + create_test_points(points2, arg2); + create_test_points(points3, arg3); + it_type a = points1.begin(); + it_type b = points1.end(); + row_type row; + while(a != b) + { + it_type c = points2.begin(); + it_type d = points2.end(); + while(c != d) + { + it_type e = points3.begin(); + it_type f = points3.end(); + while(e != f) + { + if((arg1.type & dummy_param) == 0) + row.push_back(*a); + if((arg2.type & dummy_param) == 0) + row.push_back(*c); + if((arg3.type & dummy_param) == 0) + row.push_back(*e); + try{ + // domain_error exceptions from func are swallowed + // and this data point is ignored: + detail::unpack_and_append(row, func(*a, *c, *e)); + m_data.insert(row); + } + catch(const std::domain_error&){} + row.clear(); + ++e; + } + ++c; + } + ++a; + } + return *this; + } + + void clear(){ m_data.clear(); } + + // access: + iterator begin() { return m_data.begin(); } + iterator end() { return m_data.end(); } + const_iterator begin()const { return m_data.begin(); } + const_iterator end()const { return m_data.end(); } + bool operator==(const test_data& d)const{ return m_data == d.m_data; } + bool operator!=(const test_data& d)const{ return m_data != d.m_data; } + void swap(test_data& other){ m_data.swap(other.m_data); } + size_type size()const{ return m_data.size(); } + size_type max_size()const{ return m_data.max_size(); } + bool empty()const{ return m_data.empty(); } + + bool operator < (const test_data& dat)const{ return m_data < dat.m_data; } + bool operator <= (const test_data& dat)const{ return m_data <= dat.m_data; } + bool operator > (const test_data& dat)const{ return m_data > dat.m_data; } + bool operator >= (const test_data& dat)const{ return m_data >= dat.m_data; } + +private: + void create_test_points(std::set& points, const parameter_info& arg1); + std::set m_data; + + static float extern_val; + static float truncate_to_float(float const * pf); + static float truncate_to_float(float c){ return truncate_to_float(&c); } +}; + +// +// This code exists to bemuse the compiler's optimizer and force a +// truncation to float-precision only: +// +template +inline float test_data::truncate_to_float(float const * pf) +{ + extern_val = *pf; + return *pf; +} + +template +float test_data::extern_val = 0; + +template +void test_data::create_test_points(std::set& points, const parameter_info& arg1) +{ + BOOST_MATH_STD_USING + // + // Generate a set of test points as requested, try and generate points + // at only float precision: otherwise when testing float versions of functions + // there will be a rounding error in our input values which throws off the results + // (Garbage in garbage out etc). + // + switch(arg1.type & 0x7F) + { + case random_in_range: + { + BOOST_ASSERT(arg1.z1 < arg1.z2); + BOOST_ASSERT(arg1.n1 > 0); + typedef float random_type; + + std::tr1::mt19937 rnd; + std::tr1::uniform_real ur_a(real_cast(arg1.z1), real_cast(arg1.z2)); + std::tr1::variate_generator > gen(rnd, ur_a); + + for(int i = 0; i < arg1.n1; ++i) + { + random_type r = gen(); + points.insert(truncate_to_float(r)); + } + } + break; + case periodic_in_range: + { + BOOST_ASSERT(arg1.z1 < arg1.z2); + BOOST_ASSERT(arg1.n1 > 0); + float interval = real_cast((arg1.z2 - arg1.z1) / arg1.n1); + T val = arg1.z1; + while(val < arg1.z2) + { + points.insert(truncate_to_float(real_cast(val))); + val += interval; + } + } + break; + case power_series: + { + BOOST_ASSERT(arg1.n1 < arg1.n2); + + typedef float random_type; + typedef typename boost::mpl::if_< + ::boost::is_floating_point, + T, long double>::type power_type; + + std::tr1::mt19937 rnd; + std::tr1::uniform_real ur_a(1.0, 2.0); + std::tr1::variate_generator > gen(rnd, ur_a); + + for(int power = arg1.n1; power <= arg1.n2; ++power) + { + random_type r = gen(); + power_type p = ldexp(static_cast(r), power); + points.insert(truncate_to_float(real_cast(arg1.z1 + p))); + } + } + break; + default: + BOOST_ASSERT(0 == "Invalid parameter_info object"); + // Assert will fail if get here. + // Triggers warning 4130) // '==' : logical operation on address of string constant. + } +} + +// +// Prompt a user for information on a parameter range: +// +template +bool get_user_parameter_info(parameter_info& info, const char* param_name) +{ +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) +#endif + std::string line; + do{ + std::cout << "What kind of distribution do you require for parameter " << param_name << "?\n" + "Choices are:\n" + " r Random values in a half open range\n" + " p Evenly spaced periodic values in a half open range\n" + " e Exponential power series at a particular point: a + 2^b for some range of b\n" + "[Default=r]"; + + std::getline(std::cin, line); + boost::algorithm::trim(line); + + if(line == "r") + { + info.type = random_in_range; + break; + } + else if(line == "p") + { + info.type = periodic_in_range; + break; + } + else if(line == "e") + { + info.type = power_series; + break; + } + else if(line == "") + { + info.type = random_in_range; + break; + } + // + // Ooops, not a valid input.... + // + std::cout << "Sorry don't recognise \"" << line << "\" as a valid input\n" + "do you want to try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "n") + return false; + else if(line == "y") + continue; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + }while(true); + + switch(info.type & ~dummy_param) + { + case random_in_range: + case periodic_in_range: + // get start and end points of range: + do{ + std::cout << "Data will be in the half open range a <= x < b,\n" + "enter value for the start point fo the range [default=0]:"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "") + { + info.z1 = 0; + break; + } + try{ + info.z1 = boost::lexical_cast(line); + break; + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + }while(true); + do{ + std::cout << "Enter value for the end point fo the range [default=1]:"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "") + { + info.z2 = 1; + } + else + { + try + { + info.z2 = boost::lexical_cast(line); + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + } + if(info.z1 >= info.z2) + { + std::cout << "The end point of the range was <= the start point\n" + "try a different value for the endpoint [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + break; + }while(true); + do{ + // get the number of points: + std::cout << "How many data points do you want?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + try{ + info.n1 = boost::lexical_cast(line); + info.n2 = 0; + if(info.n1 <= 0) + { + std::cout << "The number of points should be > 0\n" + "try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + break; + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + }while(true); + break; + case power_series: + // get start and end points of range: + info.z2 = 0; + do{ + std::cout << "Data will be in the form a + r*2^b\n" + "for random value r,\n" + "enter value for the point a [default=0]:"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "") + { + info.z1 = 0; + break; + } + try{ + info.z1 = boost::lexical_cast(line); + break; + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + }while(true); + + do{ + std::cout << "Data will be in the form a + r*2^b\n" + "for random value r,\n" + "enter value for the starting exponent b:"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + try{ + info.n1 = boost::lexical_cast(line); + break; + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + }while(true); + + do{ + std::cout << "Data will be in the form a + r*2^b\n" + "for random value r,\n" + "enter value for the ending exponent b:"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + try{ + info.n2 = boost::lexical_cast(line); + break; + } + catch(const boost::bad_lexical_cast&) + { + std::cout << "Sorry, that was not valid input, try again [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "y") + continue; + if(line == "n") + return false; + std::cout << "Sorry don't recognise that either, giving up...\n\n"; + return false; + } + }while(true); + + break; + default: + BOOST_ASSERT(0); // should never get here!! + } + + return true; +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +} + +template +inline std::basic_ostream& write_csv(std::basic_ostream& os, + const test_data& data) +{ + const charT defarg[] = { ',', ' ', '\0' }; + return write_csv(os, data, defarg); +} + +template +std::basic_ostream& write_csv(std::basic_ostream& os, + const test_data& data, + const charT* separator) +{ + typedef typename test_data::const_iterator it_type; + typedef typename test_data::value_type value_type; + typedef typename value_type::const_iterator value_type_iterator; + it_type a, b; + a = data.begin(); + b = data.end(); + while(a != b) + { + value_type_iterator x, y; + bool sep = false; + x = a->begin(); + y = a->end(); + while(x != y) + { + if(sep) + os << separator; + os << *x; + sep = true; + ++x; + } + os << std::endl; + ++a; + } + return os; +} + +template +std::ostream& write_code(std::ostream& os, + const test_data& data, + const char* name) +{ + typedef typename test_data::const_iterator it_type; + typedef typename test_data::value_type value_type; + typedef typename value_type::const_iterator value_type_iterator; + + BOOST_ASSERT(os.good()); + + it_type a, b; + a = data.begin(); + b = data.end(); + if(a == b) + return os; + + os << "#define SC_(x) static_cast(BOOST_JOIN(x, L))\n" + " static const boost::arraysize() << ">, " << data.size() << "> " << name << " = {{\n"; + + while(a != b) + { + if(a != data.begin()) + os << ", \n"; + + value_type_iterator x, y; + x = a->begin(); + y = a->end(); + os << " { "; + while(x != y) + { + if(x != a->begin()) + os << ", "; + os << "SC_(" << *x << ")"; + ++x; + } + os << " }"; + ++a; + } + os << "\n }};\n#undef SC_\n\n"; + return os; +} + +} // namespace tools +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + +#endif // BOOST_MATH_TOOLS_TEST_DATA_HPP + diff --git a/include/boost/math/tools/toms748_solve.hpp b/include/boost/math/tools/toms748_solve.hpp new file mode 100644 index 000000000..b52c4ba9f --- /dev/null +++ b/include/boost/math/tools/toms748_solve.hpp @@ -0,0 +1,579 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_SOLVE_ROOT_HPP +#define BOOST_MATH_TOOLS_SOLVE_ROOT_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost{ namespace math{ namespace tools{ + +template +class eps_tolerance +{ +public: + eps_tolerance(unsigned bits) + { + BOOST_MATH_STD_USING + eps = (std::max)(T(ldexp(1.0F, 1-bits)), 2 * tools::epsilon()); + } + bool operator()(const T& a, const T& b) + { + BOOST_MATH_STD_USING + return (fabs(a - b) / (std::min)(fabs(a), fabs(b))) <= eps; + } +private: + T eps; +}; + +struct equal_floor +{ + equal_floor(){} + template + bool operator()(const T& a, const T& b) + { + BOOST_MATH_STD_USING + return floor(a) == floor(b); + } +}; + +struct equal_ceil +{ + equal_ceil(){} + template + bool operator()(const T& a, const T& b) + { + BOOST_MATH_STD_USING + return ceil(a) == ceil(b); + } +}; + +struct equal_nearest_integer +{ + equal_nearest_integer(){} + template + bool operator()(const T& a, const T& b) + { + BOOST_MATH_STD_USING + return floor(a + 0.5f) == floor(b + 0.5f); + } +}; + +namespace detail{ + +template +void bracket(F f, T& a, T& b, T c, T& fa, T& fb, T& d, T& fd) +{ + // + // Given a point c inside the existing enclosing interval + // [a, b] sets a = c if f(c) == 0, otherwise finds the new + // enclosing interval: either [a, c] or [c, b] and sets + // d and fd to the point that has just been removed from + // the interval. In other words d is the third best guess + // to the root. + // + BOOST_MATH_STD_USING // For ADL of std math functions + T tol = tools::epsilon() * 2; + // + // If the interval [a,b] is very small, or if c is too close + // to one end of the interval then we need to adjust the + // location of c accordingly: + // + if((b - a) < 2 * tol * a) + { + c = a + (b - a) / 2; + } + else if(c <= a + fabs(a) * tol) + { + c = a * (1 + tol); + } + else if(c >= b - fabs(b) * tol) + { + c = b * (1 - tol); + } + // + // OK, lets invoke f(c): + // + T fc = f(c); + // + // if we have a zero then we have an exact solution to the root: + // + if(fc == 0) + { + a = c; + fa = 0; + d = 0; + fd = 0; + return; + } + // + // Non-zero fc, update the interval: + // + if(boost::math::sign(fa) * boost::math::sign(fc) < 0) + { + d = b; + fd = fb; + b = c; + fb = fc; + } + else + { + d = a; + fd = fa; + a = c; + fa= fc; + } +} + +template +inline T safe_div(T num, T denom, T r) +{ + // + // return num / denom without overflow, + // return r if overflow would occur. + // + BOOST_MATH_STD_USING // For ADL of std math functions + + if(fabs(denom) < 1) + { + if(fabs(denom * tools::max_value()) <= fabs(num)) + return r; + } + return num / denom; +} + +template +inline T secant_interpolate(const T& a, const T& b, const T& fa, const T& fb) +{ + // + // Performs standard secant interpolation of [a,b] given + // function evaluations f(a) and f(b). Performs a bisection + // if secant interpolation would leave us very close to either + // a or b. Rationale: we only call this function when at least + // one other form of interpolation has already failed, so we know + // that the function is unlikely to be smooth with a root very + // close to a or b. + // + BOOST_MATH_STD_USING // For ADL of std math functions + + T tol = tools::epsilon() * 5; + T c = a - (fa / (fb - fa)) * (b - a); + if((c <= a + fabs(a) * tol) || (c >= b - fabs(b) * tol)) + return (a + b) / 2; + return c; +} + +template +T quadratic_interpolate(const T& a, const T& b, T const& d, + const T& fa, const T& fb, T const& fd, + unsigned count) +{ + // + // Performs quadratic interpolation to determine the next point, + // takes count Newton steps to find the location of the + // quadratic polynomial. + // + // Point d must lie outside of the interval [a,b], it is the third + // best approximation to the root, after a and b. + // + // Note: this does not guarentee to find a root + // inside [a, b], so we fall back to a secant step should + // the result be out of range. + // + // Start by obtaining the coefficients of the quadratic polynomial: + // + T B = safe_div(fb - fa, b - a, tools::max_value()); + T A = safe_div(fd - fb, d - b, tools::max_value()); + A = safe_div(A - B, d - a, T(0)); + + if(a == 0) + { + // failure to determine coefficients, try a secant step: + return secant_interpolate(a, b, fa, fb); + } + // + // Determine the starting point of the Newton steps: + // + T c; + if(boost::math::sign(A) * boost::math::sign(fa) > 0) + { + c = a; + } + else + { + c = b; + } + // + // Take the Newton steps: + // + for(unsigned i = 1; i <= count; ++i) + { + //c -= safe_div(B * c, (B + A * (2 * c - a - b)), 1 + c - a); + c -= safe_div(fa+(B+A*(c-b))*(c-a), (B + A * (2 * c - a - b)), 1 + c - a); + } + if((c <= a) || (c >= b)) + { + // Oops, failure, try a secant step: + c = secant_interpolate(a, b, fa, fb); + } + return c; +} + +template +T cubic_interpolate(const T& a, const T& b, const T& d, + const T& e, const T& fa, const T& fb, + const T& fd, const T& fe) +{ + // + // Uses inverse cubic interpolation of f(x) at points + // [a,b,d,e] to obtain an approximate root of f(x). + // Points d and e lie outside the interval [a,b] + // and are the third and forth best approximations + // to the root that we have found so far. + // + // Note: this does not guarentee to find a root + // inside [a, b], so we fall back to quadratic + // interpolation in case of an erroneous result. + // + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b + << " d = " << d << " e = " << e << " fa = " << fa << " fb = " << fb + << " fd = " << fd << " fe = " << fe); + T q11 = (d - e) * fd / (fe - fd); + T q21 = (b - d) * fb / (fd - fb); + T q31 = (a - b) * fa / (fb - fa); + T d21 = (b - d) * fd / (fd - fb); + T d31 = (a - b) * fb / (fb - fa); + BOOST_MATH_INSTRUMENT_CODE( + "q11 = " << q11 << " q21 = " << q21 << " q31 = " << q31 + << " d21 = " << d21 << " d31 = " << d31); + T q22 = (d21 - q11) * fb / (fe - fb); + T q32 = (d31 - q21) * fa / (fd - fa); + T d32 = (d31 - q21) * fd / (fd - fa); + T q33 = (d32 - q22) * fa / (fe - fa); + T c = q31 + q32 + q33 + a; + BOOST_MATH_INSTRUMENT_CODE( + "q22 = " << q22 << " q32 = " << q32 << " d32 = " << d32 + << " q33 = " << q33 << " c = " << c); + + if((c <= a) || (c >= b)) + { + // Out of bounds step, fall back to quadratic interpolation: + c = quadratic_interpolate(a, b, d, fa, fb, fd, 3); + BOOST_MATH_INSTRUMENT_CODE( + "Out of bounds interpolation, falling back to quadratic interpolation. c = " << c); + } + + return c; +} + +} // namespace detail + +template +std::pair toms748_solve(F f, const T& ax, const T& bx, const T& fax, const T& fbx, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) +{ + // + // Main entry point and logic for Toms Algorithm 748 + // root finder. + // + BOOST_MATH_STD_USING // For ADL of std math functions + + static const char* function = "boost::math::tools::toms748_solve<%1%>"; + + boost::uintmax_t count = max_iter; + T a, b, fa, fb, c, u, fu, a0, b0, d, fd, e, fe; + static const T mu = 0.5f; + + // initialise a, b and fa, fb: + a = ax; + b = bx; + if(a >= b) + policies::raise_domain_error( + function, + "Parameters a and b out of order: a=%1%", a, pol); + fa = fax; + fb = fbx; + + if(tol(a, b) || (fa == 0) || (fb == 0)) + { + max_iter = 0; + if(fa == 0) + b = a; + else if(fb == 0) + a = b; + return std::make_pair(a, b); + } + + if(boost::math::sign(fa) * boost::math::sign(fb) > 0) + policies::raise_domain_error( + function, + "Parameters a and b do not bracket the root: a=%1%", a, pol); + // dummy value for fd, e and fe: + fe = e = fd = 1e5F; + + if(fa != 0) + { + // + // On the first step we take a secant step: + // + c = detail::secant_interpolate(a, b, fa, fb); + detail::bracket(f, a, b, c, fa, fb, d, fd); + --count; + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + + if(count && (fa != 0) && !tol(a, b)) + { + // + // On the second step we take a quadratic interpolation: + // + c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 2); + e = d; + fe = fd; + detail::bracket(f, a, b, c, fa, fb, d, fd); + --count; + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + } + } + + while(count && (fa != 0) && !tol(a, b)) + { + // save our brackets: + a0 = a; + b0 = b; + // + // Starting with the third step taken + // we can use either quadratic or cubic interpolation. + // Cubic interpolation requires that all four function values + // fa, fb, fd, and fe are distinct, should that not be the case + // then variable prof will get set to true, and we'll end up + // taking a quadratic step instead. + // + T min_diff = tools::min_value() * 32; + bool prof = (fabs(fa - fb) < min_diff) || (fabs(fa - fd) < min_diff) || (fabs(fa - fe) < min_diff) || (fabs(fb - fd) < min_diff) || (fabs(fb - fe) < min_diff) || (fabs(fd - fe) < min_diff); + if(prof) + { + c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 2); + BOOST_MATH_INSTRUMENT_CODE("Can't take cubic step!!!!"); + } + else + { + c = detail::cubic_interpolate(a, b, d, e, fa, fb, fd, fe); + } + // + // re-bracket, and check for termination: + // + e = d; + fe = fd; + detail::bracket(f, a, b, c, fa, fb, d, fd); + if((0 == --count) || (fa == 0) || tol(a, b)) + break; + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + // + // Now another interpolated step: + // + prof = (fabs(fa - fb) < min_diff) || (fabs(fa - fd) < min_diff) || (fabs(fa - fe) < min_diff) || (fabs(fb - fd) < min_diff) || (fabs(fb - fe) < min_diff) || (fabs(fd - fe) < min_diff); + if(prof) + { + c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 3); + BOOST_MATH_INSTRUMENT_CODE("Can't take cubic step!!!!"); + } + else + { + c = detail::cubic_interpolate(a, b, d, e, fa, fb, fd, fe); + } + // + // Bracket again, and check termination condition, update e: + // + detail::bracket(f, a, b, c, fa, fb, d, fd); + if((0 == --count) || (fa == 0) || tol(a, b)) + break; + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + // + // Now we take a double-length secant step: + // + if(fabs(fa) < fabs(fb)) + { + u = a; + fu = fa; + } + else + { + u = b; + fu = fb; + } + c = u - 2 * (fu / (fb - fa)) * (b - a); + if(fabs(c - u) > (b - a) / 2) + { + c = a + (b - a) / 2; + } + // + // Bracket again, and check termination condition: + // + e = d; + fe = fd; + detail::bracket(f, a, b, c, fa, fb, d, fd); + if((0 == --count) || (fa == 0) || tol(a, b)) + break; + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + // + // And finally... check to see if an additional bisection step is + // to be taken, we do this if we're not converging fast enough: + // + if((b - a) < mu * (b0 - a0)) + continue; + // + // bracket again on a bisection: + // + e = d; + fe = fd; + detail::bracket(f, a, b, a + (b - a) / 2, fa, fb, d, fd); + --count; + BOOST_MATH_INSTRUMENT_CODE("Not converging: Taking a bisection!!!!"); + BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b); + } // while loop + + max_iter -= count; + if(fa == 0) + { + b = a; + } + else if(fb == 0) + { + a = b; + } + return std::make_pair(a, b); +} + +template +inline std::pair toms748_solve(F f, const T& ax, const T& bx, const T& fax, const T& fbx, Tol tol, boost::uintmax_t& max_iter) +{ + return toms748_solve(f, ax, bx, fax, fbx, tol, max_iter, policies::policy<>()); +} + +template +inline std::pair toms748_solve(F f, const T& ax, const T& bx, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) +{ + max_iter -= 2; + std::pair r = toms748_solve(f, ax, bx, f(ax), f(bx), tol, max_iter, pol); + max_iter += 2; + return r; +} + +template +inline std::pair toms748_solve(F f, const T& ax, const T& bx, Tol tol, boost::uintmax_t& max_iter) +{ + return toms748_solve(f, ax, bx, tol, max_iter, policies::policy<>()); +} + +template +std::pair bracket_and_solve_root(F f, const T& guess, T factor, bool rising, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) +{ + BOOST_MATH_STD_USING + static const char* function = "boost::math::tools::bracket_and_solve_root<%1%>"; + // + // Set up inital brackets: + // + T a = guess; + T b = a; + T fa = f(a); + T fb = fa; + // + // Set up invocation count: + // + boost::uintmax_t count = max_iter - 1; + + if((fa < 0) == (guess < 0 ? !rising : rising)) + { + // + // Zero is to the right of b, so walk upwards + // until we find it: + // + while((boost::math::sign)(fb) == (boost::math::sign)(fa)) + { + if(count == 0) + policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, pol); + // + // Heuristic: every 20 iterations we double the growth factor in case the + // initial guess was *really* bad ! + // + if((max_iter - count) % 20 == 0) + factor *= 2; + // + // Now go ahead and move are guess by "factor": + // + a = b; + fa = fb; + b *= factor; + fb = f(b); + --count; + BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count); + } + } + else + { + // + // Zero is to the left of a, so walk downwards + // until we find it: + // + while((boost::math::sign)(fb) == (boost::math::sign)(fa)) + { + if(fabs(a) < tools::min_value()) + { + // Escape route just in case the answer is zero! + max_iter -= count; + max_iter += 1; + return a > 0 ? std::make_pair(T(0), T(a)) : std::make_pair(T(a), T(0)); + } + if(count == 0) + policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, pol); + // + // Heuristic: every 20 iterations we double the growth factor in case the + // initial guess was *really* bad ! + // + if((max_iter - count) % 20 == 0) + factor *= 2; + // + // Now go ahead and move are guess by "factor": + // + b = a; + fb = fa; + a /= factor; + fa = f(a); + --count; + BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count); + } + } + max_iter -= count; + max_iter += 1; + std::pair r = toms748_solve( + f, + (a < 0 ? b : a), + (a < 0 ? a : b), + (a < 0 ? fb : fa), + (a < 0 ? fa : fb), + tol, + count, + pol); + max_iter += count; + BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count); + return r; +} + +template +inline std::pair bracket_and_solve_root(F f, const T& guess, const T& factor, bool rising, Tol tol, boost::uintmax_t& max_iter) +{ + return bracket_and_solve_root(f, guess, factor, rising, tol, max_iter, policies::policy<>()); +} + +} // namespace tools +} // namespace math +} // namespace boost + + +#endif // BOOST_MATH_TOOLS_SOLVE_ROOT_HPP diff --git a/include/boost/math/tools/traits.hpp b/include/boost/math/tools/traits.hpp new file mode 100644 index 000000000..766ea31f0 --- /dev/null +++ b/include/boost/math/tools/traits.hpp @@ -0,0 +1,106 @@ +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* +This header defines two traits classes, both in namespace boost::math::tools. + +is_distribution::value is true iff D has overloaded "cdf" and +"quantile" functions, plus member typedefs value_type and policy_type. +It's not much of a definitive test frankly, +but if it looks like a distribution and quacks like a distribution +then it must be a distribution. + +is_scaled_distribution::value is true iff D is a distribution +as defined above, and has member functions "scale" and "location". + +*/ + +#ifndef BOOST_STATS_IS_DISTRIBUTION_HPP +#define BOOST_STATS_IS_DISTRIBUTION_HPP + +#include +// should be the last #include +#include + +namespace boost{ namespace math{ namespace tools{ + +namespace detail{ + +BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_value_type, value_type, true); +BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_policy_type, policy_type, true); + +template +char cdf(const D& ...); +template +char quantile(const D& ...); + +template +struct has_cdf +{ + static D d; + BOOST_STATIC_CONSTANT(bool, value = sizeof(cdf(d, 0.0f)) != 1); +}; + +template +struct has_quantile +{ + static D d; + BOOST_STATIC_CONSTANT(bool, value = sizeof(quantile(d, 0.0f)) != 1); +}; + +template +struct is_distribution_imp +{ + BOOST_STATIC_CONSTANT(bool, value = + has_quantile::value + && has_cdf::value + && has_value_type::value + && has_policy_type::value); +}; + +template +struct result_tag{}; + +template +double test_has_location(const volatile result_tag*); +template +char test_has_location(...); + +template +double test_has_scale(const volatile result_tag*); +template +char test_has_scale(...); + +template +struct is_scaled_distribution_helper +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +struct is_scaled_distribution_helper +{ + BOOST_STATIC_CONSTANT(bool, value = + (sizeof(test_has_location(0)) != 1) + && + (sizeof(test_has_scale(0)) != 1)); +}; + +template +struct is_scaled_distribution_imp +{ + BOOST_STATIC_CONSTANT(bool, value = (::boost::math::tools::detail::is_scaled_distribution_helper::value>::value)); +}; + +} // namespace detail + +BOOST_TT_AUX_BOOL_TRAIT_DEF1(is_distribution,T,::boost::math::tools::detail::is_distribution_imp::value) +BOOST_TT_AUX_BOOL_TRAIT_DEF1(is_scaled_distribution,T,::boost::math::tools::detail::is_scaled_distribution_imp::value) + +}}} + +#endif + diff --git a/include/boost/math/tools/user.hpp b/include/boost/math/tools/user.hpp new file mode 100644 index 000000000..bcf78b389 --- /dev/null +++ b/include/boost/math/tools/user.hpp @@ -0,0 +1,92 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_USER_HPP +#define BOOST_MATH_TOOLS_USER_HPP + +// This file can be modified by the user to change the default policies. +// See "Changing the Policy Defaults" in documentation. + +// define this if the platform has no long double functions, +// or if the long double versions have only double precision: +// +// #define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +// +// Performance tuning options: +// +// #define BOOST_MATH_POLY_METHOD 3 +// #define BOOST_MATH_RATIONAL_METHOD 3 +// +// The maximum order of polynomial that will be evaluated +// via an unrolled specialisation: +// +// #define BOOST_MATH_MAX_POLY_ORDER 17 +// +// decide whether to store constants as integers or reals: +// +// #define BOOST_MATH_INT_TABLE_TYPE(RT, IT) IT + +// +// Default policies follow: +// +// Domain errors: +// +// #define BOOST_MATH_DOMAIN_ERROR_POLICY throw_on_error +// +// Pole errors: +// +// #define BOOST_MATH_POLE_ERROR_POLICY throw_on_error +// +// Overflow Errors: +// +// #define BOOST_MATH_OVERFLOW_ERROR_POLICY throw_on_error +// +// Internal Evaluation Errors: +// +// #define BOOST_MATH_EVALUATION_ERROR_POLICY throw_on_error +// +// Underfow: +// +// #define BOOST_MATH_UNDERFLOW_ERROR_POLICY ignore_error +// +// Denorms: +// +// #define BOOST_MATH_DENORM_ERROR_POLICY ignore_error +// +// Max digits to use for internal calculations: +// +// #define BOOST_MATH_DIGITS10_POLICY 0 +// +// Promote floats to doubles internally? +// +// #define BOOST_MATH_PROMOTE_FLOAT_POLICY true +// +// Promote doubles to long double internally: +// +// #define BOOST_MATH_PROMOTE_DOUBLE_POLICY true +// +// What do discrete quantiles return? +// +// #define BOOST_MATH_DISCRETE_QUANTILE_POLICY integer_round_outwards +// +// If a function is mathematically undefined +// (for example the Cauchy distribution has no mean), +// then do we stop the code from compiling? +// +// #define BOOST_MATH_ASSERT_UNDEFINED_POLICY true +// +// Maximum series iterstions permitted: +// +// #define BOOST_MATH_MAX_SERIES_ITERATION_POLICY 1000000 +// +// Maximum root finding steps permitted: +// +// define BOOST_MATH_MAX_ROOT_ITERATION_POLICY 200 + +#endif // BOOST_MATH_TOOLS_USER_HPP + diff --git a/include/boost/math/tools/workaround.hpp b/include/boost/math/tools/workaround.hpp new file mode 100644 index 000000000..4e0035f8e --- /dev/null +++ b/include/boost/math/tools/workaround.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2006-7 John Maddock +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TOOLS_WORHAROUND_HPP +#define BOOST_MATH_TOOLS_WORHAROUND_HPP + +#include + +namespace boost{ namespace math{ namespace tools{ +// +// We call this short forwarding function so that we can work around a bug +// on Darwin that causes std::fmod to return a NaN. The test case is: +// std::fmod(1185.0L, 1.5L); +// +template +inline T fmod_workaround(T a, T b) +{ + BOOST_MATH_STD_USING + return fmod(a, b); +} +#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106)) +template <> +inline long double fmod_workaround(long double a, long double b) +{ + return ::fmodl(a, b); +} +#endif + +}}} // namespaces + +#endif // BOOST_MATH_TOOLS_WORHAROUND_HPP