log1p.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 469 行

HPP
469
字号
//  (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_LOG1P_INCLUDED#define BOOST_MATH_LOG1P_INCLUDED#ifdef _MSC_VER#pragma once#endif#include <boost/config/no_tr1/cmath.hpp>#include <math.h> // platform's ::log1p#include <boost/limits.hpp>#include <boost/math/tools/config.hpp>#include <boost/math/tools/series.hpp>#include <boost/math/tools/rational.hpp>#include <boost/math/policies/error_handling.hpp>#include <boost/math/special_functions/math_fwd.hpp>#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS#  include <boost/static_assert.hpp>#else#  include <boost/assert.hpp>#endifnamespace 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 <class T>  struct log1p_series  {     typedef T result_type;     log1p_series(T x)        : k(0), m_mult(-x), m_prod(-1){}     T operator()()     {        m_prod *= m_mult;        return m_prod / ++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&);  };// 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<T>::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 <class T, class Policy>T log1p_imp(T const & x, const Policy& pol, const mpl::int_<0>&){ // The function returns the natural logarithm of 1 + x.   typedef typename tools::promote_args<T>::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<T>(         function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<T>(         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<result_type>())      return x;   detail::log1p_series<result_type> s(x);   boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) && !BOOST_WORKAROUND(__EDG_VERSION__, <= 245)   result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter);#else   result_type zero = 0;   result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter, zero);#endif   policies::check_series_iterations(function, max_iter, pol);   return result;}template <class T, class Policy>T log1p_imp(T const& x, const Policy& pol, const mpl::int_<53>&){ // The function returns the natural logarithm of 1 + x.   BOOST_MATH_STD_USING   static const char* function = "boost::math::log1p<%1%>(%1%)";   if(x < -1)      return policies::raise_domain_error<T>(         function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<T>(         function, 0, pol);   T a = fabs(x);   if(a > 0.5f)      return log(1 + x);   // Note that without numeric_limits specialisation support,    // epsilon just returns zero, and our "optimisation" will always fail:   if(a < tools::epsilon<T>())      return x;   // Maximum Deviation Found:                     1.846e-017   // Expected Error Term:                         1.843e-017   // Maximum Relative Change in Control Points:   8.138e-004   // Max Error found at double precision =        3.250766e-016   static const T P[] = {           0.15141069795941984e-16L,       0.35495104378055055e-15L,       0.33333333333332835L,       0.99249063543365859L,       1.1143969784156509L,       0.58052937949269651L,       0.13703234928513215L,       0.011294864812099712L     };   static const T Q[] = {           1L,       3.7274719063011499L,       5.5387948649720334L,       4.159201143419005L,       1.6423855110312755L,       0.31706251443180914L,       0.022665554431410243L,       -0.29252538135177773e-5L     };   T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);   result *= x;   return result;}template <class T, class Policy>T log1p_imp(T const& x, const Policy& pol, const mpl::int_<64>&){ // The function returns the natural logarithm of 1 + x.   BOOST_MATH_STD_USING   static const char* function = "boost::math::log1p<%1%>(%1%)";   if(x < -1)      return policies::raise_domain_error<T>(         function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<T>(         function, 0, pol);   T a = fabs(x);   if(a > 0.5f)      return log(1 + x);   // Note that without numeric_limits specialisation support,    // epsilon just returns zero, and our "optimisation" will always fail:   if(a < tools::epsilon<T>())      return x;   // Maximum Deviation Found:                     8.089e-20   // Expected Error Term:                         8.088e-20   // Maximum Relative Change in Control Points:   9.648e-05   // Max Error found at long double precision =   2.242324e-19   static const T P[] = {          -0.807533446680736736712e-19L,      -0.490881544804798926426e-18L,      0.333333333333333373941L,      1.17141290782087994162L,      1.62790522814926264694L,      1.13156411870766876113L,      0.408087379932853785336L,      0.0706537026422828914622L,      0.00441709903782239229447L   };   static const T Q[] = {          1L,      4.26423872346263928361L,      7.48189472704477708962L,      6.94757016732904280913L,      3.6493508622280767304L,      1.06884863623790638317L,      0.158292216998514145947L,      0.00885295524069924328658L,      -0.560026216133415663808e-6L   };   T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);   result *= x;   return result;}template <class T, class Policy>T log1p_imp(T const& x, const Policy& pol, const mpl::int_<24>&){ // The function returns the natural logarithm of 1 + x.   BOOST_MATH_STD_USING   static const char* function = "boost::math::log1p<%1%>(%1%)";   if(x < -1)      return policies::raise_domain_error<T>(         function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<T>(         function, 0, pol);   T a = fabs(x);   if(a > 0.5f)      return log(1 + x);   // Note that without numeric_limits specialisation support,    // epsilon just returns zero, and our "optimisation" will always fail:   if(a < tools::epsilon<T>())      return x;   // Maximum Deviation Found:                     6.910e-08   // Expected Error Term:                         6.910e-08   // Maximum Relative Change in Control Points:   2.509e-04   // Max Error found at double precision =        6.910422e-08   // Max Error found at float precision =         8.357242e-08   static const T P[] = {          -0.671192866803148236519e-7L,      0.119670999140731844725e-6L,      0.333339469182083148598L,      0.237827183019664122066L   };   static const T Q[] = {          1L,      1.46348272586988539733L,      0.497859871350117338894L,      -0.00471666268910169651936L   };   T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);   result *= x;   return result;}} // namespace detailtemplate <class T, class Policy>inline typename tools::promote_args<T>::type log1p(T x, const Policy&){    typedef typename tools::promote_args<T>::type result_type;   typedef typename policies::evaluation<result_type, Policy>::type value_type;   typedef typename policies::precision<result_type, Policy>::type precision_type;   typedef typename policies::normalise<      Policy,       policies::promote_float<false>,       policies::promote_double<false>,       policies::discrete_quantile<>,      policies::assert_undefined<> >::type forwarding_policy;   typedef typename mpl::if_<      mpl::less_equal<precision_type, mpl::int_<0> >,      mpl::int_<0>,      typename mpl::if_<         mpl::less_equal<precision_type, mpl::int_<53> >,         mpl::int_<53>,  // double         typename mpl::if_<            mpl::less_equal<precision_type, mpl::int_<64> >,            mpl::int_<64>, // 80-bit long double            mpl::int_<0> // too many bits, use generic version.         >::type      >::type   >::type tag_type;   return policies::checked_narrowing_cast<result_type, forwarding_policy>(      detail::log1p_imp(static_cast<value_type>(x), forwarding_policy(), tag_type()), "boost::math::log1p<%1%>(%1%)");}#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))// These overloads work around a type deduction bug:inline float log1p(float z){   return log1p<float>(z);}inline double log1p(double z){   return log1p<double>(z);}#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONSinline long double log1p(long double z){   return log1p<long double>(z);}#endif#endif#ifdef log1p#  ifndef BOOST_HAS_LOG1P#     define BOOST_HAS_LOG1P#  endif#  undef log1p#endif#if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER))#  if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) \   || ((defined(linux) || defined(__linux) || defined(__linux__)) && !defined(__SUNPRO_CC)) \   || (defined(__hpux) && !defined(__hppa))template <class Policy>inline float log1p(float x, const Policy& pol){    if(x < -1)      return policies::raise_domain_error<float>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<float>(         "log1p<%1%>(%1%)", 0, pol);   return ::log1pf(x); }#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONStemplate <class Policy>inline long double log1p(long double x, const Policy& pol){    if(x < -1)      return policies::raise_domain_error<long double>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<long double>(         "log1p<%1%>(%1%)", 0, pol);   return ::log1pl(x); }#endif#elsetemplate <class Policy>inline float log1p(float x, const Policy& pol){    if(x < -1)      return policies::raise_domain_error<float>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<float>(         "log1p<%1%>(%1%)", 0, pol);   return ::log1p(x); }#endiftemplate <class Policy>inline double log1p(double x, const Policy& pol){    if(x < -1)      return policies::raise_domain_error<double>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<double>(         "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 <class Policy>inline double log1p(double x, const Policy& pol){   if(x < -1)      return policies::raise_domain_error<double>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<double>(         "log1p<%1%>(%1%)", 0, pol);   double u = 1+x;   if(u == 1.0)       return x;    else      return log(u)*(x/(u-1.0));}template <class Policy>inline float log1p(float x, const Policy& pol){   return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));}template <class Policy>inline long double log1p(long double x, const Policy& pol){   if(x < -1)      return policies::raise_domain_error<long double>(         "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<long double>(         "log1p<%1%>(%1%)", 0, pol);   long double u = 1+x;   if(u == 1.0)       return x;    else      return log(u)*(x/(u-1.0));}#endiftemplate <class T>inline typename tools::promote_args<T>::type log1p(T x){   return boost::math::log1p(x, policies::policy<>());}//// Compute log(1+x)-x://template <class T, class Policy>inline typename tools::promote_args<T>::type    log1pmx(T x, const Policy& pol){   typedef typename tools::promote_args<T>::type result_type;   BOOST_MATH_STD_USING   static const char* function = "boost::math::log1pmx<%1%>(%1%)";   if(x < -1)      return policies::raise_domain_error<T>(         function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);   if(x == -1)      return -policies::raise_overflow_error<T>(         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<result_type>())      return -x * x / 2;   boost::math::detail::log1p_series<T> s(x);   s();   boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))   T zero = 0;   T result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter, zero);#else   T result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter);#endif   policies::check_series_iterations(function, max_iter, pol);   return result;}template <class T>inline typename tools::promote_args<T>::type log1pmx(T x){   return log1pmx(x, policies::policy<>());}} // namespace math} // namespace boost#endif // BOOST_MATH_LOG1P_INCLUDED

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?