Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:17

0001 //  (C) Copyright John Maddock 2005-2006.
0002 //  Use, modification and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MATH_LOG1P_INCLUDED
0007 #define BOOST_MATH_LOG1P_INCLUDED
0008 
0009 #ifdef _MSC_VER
0010 #pragma once
0011 #pragma warning(push)
0012 #pragma warning(disable:4702) // Unreachable code (release mode only warning)
0013 #endif
0014 
0015 #include <cmath>
0016 #include <cstdint>
0017 #include <limits>
0018 #include <boost/math/tools/config.hpp>
0019 #include <boost/math/tools/series.hpp>
0020 #include <boost/math/tools/rational.hpp>
0021 #include <boost/math/tools/big_constant.hpp>
0022 #include <boost/math/policies/error_handling.hpp>
0023 #include <boost/math/special_functions/math_fwd.hpp>
0024 #include <boost/math/tools/assert.hpp>
0025 #include <boost/math/special_functions/fpclassify.hpp>
0026 
0027 #if defined(__GNUC__) && defined(BOOST_MATH_USE_FLOAT128)
0028 //
0029 // This is the only way we can avoid
0030 // warning: non-standard suffix on floating constant [-Wpedantic]
0031 // when building with -Wall -pedantic.  Neither __extension__
0032 // nor #pragma diagnostic ignored work :(
0033 //
0034 #pragma GCC system_header
0035 #endif
0036 
0037 namespace boost{ namespace math{
0038 
0039 namespace detail
0040 {
0041   // Functor log1p_series returns the next term in the Taylor series
0042   //   pow(-1, k-1)*pow(x, k) / k
0043   // each time that operator() is invoked.
0044   //
0045   template <class T>
0046   struct log1p_series
0047   {
0048      typedef T result_type;
0049 
0050      log1p_series(T x)
0051         : k(0), m_mult(-x), m_prod(-1){}
0052 
0053      T operator()()
0054      {
0055         m_prod *= m_mult;
0056         return m_prod / ++k;
0057      }
0058 
0059      int count()const
0060      {
0061         return k;
0062      }
0063 
0064   private:
0065      int k;
0066      const T m_mult;
0067      T m_prod;
0068      log1p_series(const log1p_series&) = delete;
0069      log1p_series& operator=(const log1p_series&) = delete;
0070   };
0071 
0072 // Algorithm log1p is part of C99, but is not yet provided by many compilers.
0073 //
0074 // This version uses a Taylor series expansion for 0.5 > x > epsilon, which may
0075 // require up to std::numeric_limits<T>::digits+1 terms to be calculated.
0076 // It would be much more efficient to use the equivalence:
0077 //   log(1+x) == (log(1+x) * x) / ((1-x) - 1)
0078 // Unfortunately many optimizing compilers make such a mess of this, that
0079 // it performs no better than log(1+x): which is to say not very well at all.
0080 //
0081 template <class T, class Policy>
0082 T log1p_imp(T const & x, const Policy& pol, const std::integral_constant<int, 0>&)
0083 { // The function returns the natural logarithm of 1 + x.
0084    typedef typename tools::promote_args<T>::type result_type;
0085    BOOST_MATH_STD_USING
0086 
0087    static const char* function = "boost::math::log1p<%1%>(%1%)";
0088 
0089    if((x < -1) || (boost::math::isnan)(x))
0090       return policies::raise_domain_error<T>(
0091          function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0092    if(x == -1)
0093       return -policies::raise_overflow_error<T>(
0094          function, nullptr, pol);
0095 
0096    result_type a = abs(result_type(x));
0097    if(a > result_type(0.5f))
0098       return log(1 + result_type(x));
0099    // Note that without numeric_limits specialisation support,
0100    // epsilon just returns zero, and our "optimisation" will always fail:
0101    if(a < tools::epsilon<result_type>())
0102       return x;
0103    detail::log1p_series<result_type> s(x);
0104    std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0105 
0106    result_type result = tools::sum_series(s, policies::get_epsilon<result_type, Policy>(), max_iter);
0107 
0108    policies::check_series_iterations<T>(function, max_iter, pol);
0109    return result;
0110 }
0111 
0112 template <class T, class Policy>
0113 T log1p_imp(T const& x, const Policy& pol, const std::integral_constant<int, 53>&)
0114 { // The function returns the natural logarithm of 1 + x.
0115    BOOST_MATH_STD_USING
0116 
0117    static const char* function = "boost::math::log1p<%1%>(%1%)";
0118 
0119    if(x < -1)
0120       return policies::raise_domain_error<T>(
0121          function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0122    if(x == -1)
0123       return -policies::raise_overflow_error<T>(
0124          function, nullptr, pol);
0125 
0126    T a = fabs(x);
0127    if(a > 0.5f)
0128       return log(1 + x);
0129    // Note that without numeric_limits specialisation support,
0130    // epsilon just returns zero, and our "optimisation" will always fail:
0131    if(a < tools::epsilon<T>())
0132       return x;
0133 
0134    // Maximum Deviation Found:                     1.846e-017
0135    // Expected Error Term:                         1.843e-017
0136    // Maximum Relative Change in Control Points:   8.138e-004
0137    // Max Error found at double precision =        3.250766e-016
0138    static const T P[] = {
0139        static_cast<T>(0.15141069795941984e-16L),
0140        static_cast<T>(0.35495104378055055e-15L),
0141        static_cast<T>(0.33333333333332835L),
0142        static_cast<T>(0.99249063543365859L),
0143        static_cast<T>(1.1143969784156509L),
0144        static_cast<T>(0.58052937949269651L),
0145        static_cast<T>(0.13703234928513215L),
0146        static_cast<T>(0.011294864812099712L)
0147      };
0148    static const T Q[] = {
0149        static_cast<T>(1L),
0150        static_cast<T>(3.7274719063011499L),
0151        static_cast<T>(5.5387948649720334L),
0152        static_cast<T>(4.159201143419005L),
0153        static_cast<T>(1.6423855110312755L),
0154        static_cast<T>(0.31706251443180914L),
0155        static_cast<T>(0.022665554431410243L),
0156        static_cast<T>(-0.29252538135177773e-5L)
0157      };
0158 
0159    T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
0160    result *= x;
0161 
0162    return result;
0163 }
0164 
0165 template <class T, class Policy>
0166 T log1p_imp(T const& x, const Policy& pol, const std::integral_constant<int, 64>&)
0167 { // The function returns the natural logarithm of 1 + x.
0168    BOOST_MATH_STD_USING
0169 
0170    static const char* function = "boost::math::log1p<%1%>(%1%)";
0171 
0172    if(x < -1)
0173       return policies::raise_domain_error<T>(
0174          function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0175    if(x == -1)
0176       return -policies::raise_overflow_error<T>(
0177          function, nullptr, pol);
0178 
0179    T a = fabs(x);
0180    if(a > 0.5f)
0181       return log(1 + x);
0182    // Note that without numeric_limits specialisation support,
0183    // epsilon just returns zero, and our "optimisation" will always fail:
0184    if(a < tools::epsilon<T>())
0185       return x;
0186 
0187    // Maximum Deviation Found:                     8.089e-20
0188    // Expected Error Term:                         8.088e-20
0189    // Maximum Relative Change in Control Points:   9.648e-05
0190    // Max Error found at long double precision =   2.242324e-19
0191    static const T P[] = {
0192       BOOST_MATH_BIG_CONSTANT(T, 64, -0.807533446680736736712e-19),
0193       BOOST_MATH_BIG_CONSTANT(T, 64, -0.490881544804798926426e-18),
0194       BOOST_MATH_BIG_CONSTANT(T, 64, 0.333333333333333373941),
0195       BOOST_MATH_BIG_CONSTANT(T, 64, 1.17141290782087994162),
0196       BOOST_MATH_BIG_CONSTANT(T, 64, 1.62790522814926264694),
0197       BOOST_MATH_BIG_CONSTANT(T, 64, 1.13156411870766876113),
0198       BOOST_MATH_BIG_CONSTANT(T, 64, 0.408087379932853785336),
0199       BOOST_MATH_BIG_CONSTANT(T, 64, 0.0706537026422828914622),
0200       BOOST_MATH_BIG_CONSTANT(T, 64, 0.00441709903782239229447)
0201    };
0202    static const T Q[] = {
0203       BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
0204       BOOST_MATH_BIG_CONSTANT(T, 64, 4.26423872346263928361),
0205       BOOST_MATH_BIG_CONSTANT(T, 64, 7.48189472704477708962),
0206       BOOST_MATH_BIG_CONSTANT(T, 64, 6.94757016732904280913),
0207       BOOST_MATH_BIG_CONSTANT(T, 64, 3.6493508622280767304),
0208       BOOST_MATH_BIG_CONSTANT(T, 64, 1.06884863623790638317),
0209       BOOST_MATH_BIG_CONSTANT(T, 64, 0.158292216998514145947),
0210       BOOST_MATH_BIG_CONSTANT(T, 64, 0.00885295524069924328658),
0211       BOOST_MATH_BIG_CONSTANT(T, 64, -0.560026216133415663808e-6)
0212    };
0213 
0214    T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
0215    result *= x;
0216 
0217    return result;
0218 }
0219 
0220 template <class T, class Policy>
0221 T log1p_imp(T const& x, const Policy& pol, const std::integral_constant<int, 24>&)
0222 { // The function returns the natural logarithm of 1 + x.
0223    BOOST_MATH_STD_USING
0224 
0225    static const char* function = "boost::math::log1p<%1%>(%1%)";
0226 
0227    if(x < -1)
0228       return policies::raise_domain_error<T>(
0229          function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0230    if(x == -1)
0231       return -policies::raise_overflow_error<T>(
0232          function, nullptr, pol);
0233 
0234    T a = fabs(x);
0235    if(a > 0.5f)
0236       return log(1 + x);
0237    // Note that without numeric_limits specialisation support,
0238    // epsilon just returns zero, and our "optimisation" will always fail:
0239    if(a < tools::epsilon<T>())
0240       return x;
0241 
0242    // Maximum Deviation Found:                     6.910e-08
0243    // Expected Error Term:                         6.910e-08
0244    // Maximum Relative Change in Control Points:   2.509e-04
0245    // Max Error found at double precision =        6.910422e-08
0246    // Max Error found at float precision =         8.357242e-08
0247    static const T P[] = {
0248       -0.671192866803148236519e-7L,
0249       0.119670999140731844725e-6L,
0250       0.333339469182083148598L,
0251       0.237827183019664122066L
0252    };
0253    static const T Q[] = {
0254       1L,
0255       1.46348272586988539733L,
0256       0.497859871350117338894L,
0257       -0.00471666268910169651936L
0258    };
0259 
0260    T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
0261    result *= x;
0262 
0263    return result;
0264 }
0265 
0266 template <class T, class Policy, class tag>
0267 struct log1p_initializer
0268 {
0269    struct init
0270    {
0271       init()
0272       {
0273          do_init(tag());
0274       }
0275       template <int N>
0276       static void do_init(const std::integral_constant<int, N>&){}
0277       static void do_init(const std::integral_constant<int, 64>&)
0278       {
0279          boost::math::log1p(static_cast<T>(0.25), Policy());
0280       }
0281       void force_instantiate()const{}
0282    };
0283    static const init initializer;
0284    static void force_instantiate()
0285    {
0286       initializer.force_instantiate();
0287    }
0288 };
0289 
0290 template <class T, class Policy, class tag>
0291 const typename log1p_initializer<T, Policy, tag>::init log1p_initializer<T, Policy, tag>::initializer;
0292 
0293 
0294 } // namespace detail
0295 
0296 template <class T, class Policy>
0297 inline typename tools::promote_args<T>::type log1p(T x, const Policy&)
0298 {
0299    typedef typename tools::promote_args<T>::type result_type;
0300    typedef typename policies::evaluation<result_type, Policy>::type value_type;
0301    typedef typename policies::precision<result_type, Policy>::type precision_type;
0302    typedef typename policies::normalise<
0303       Policy,
0304       policies::promote_float<false>,
0305       policies::promote_double<false>,
0306       policies::discrete_quantile<>,
0307       policies::assert_undefined<> >::type forwarding_policy;
0308 
0309    typedef std::integral_constant<int,
0310       precision_type::value <= 0 ? 0 :
0311       precision_type::value <= 53 ? 53 :
0312       precision_type::value <= 64 ? 64 : 0
0313    > tag_type;
0314 
0315    detail::log1p_initializer<value_type, forwarding_policy, tag_type>::force_instantiate();
0316 
0317    return policies::checked_narrowing_cast<result_type, forwarding_policy>(
0318       detail::log1p_imp(static_cast<value_type>(x), forwarding_policy(), tag_type()), "boost::math::log1p<%1%>(%1%)");
0319 }
0320 
0321 #ifdef log1p
0322 #  ifndef BOOST_HAS_LOG1P
0323 #     define BOOST_HAS_LOG1P
0324 #  endif
0325 #  undef log1p
0326 #endif
0327 
0328 #if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER))
0329 #  ifdef BOOST_MATH_USE_C99
0330 template <class Policy>
0331 inline float log1p(float x, const Policy& pol)
0332 {
0333    if(x < -1)
0334       return policies::raise_domain_error<float>(
0335          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0336    if(x == -1)
0337       return -policies::raise_overflow_error<float>(
0338          "log1p<%1%>(%1%)", nullptr, pol);
0339    return ::log1pf(x);
0340 }
0341 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0342 template <class Policy>
0343 inline long double log1p(long double x, const Policy& pol)
0344 {
0345    if(x < -1)
0346       return policies::raise_domain_error<long double>(
0347          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0348    if(x == -1)
0349       return -policies::raise_overflow_error<long double>(
0350          "log1p<%1%>(%1%)", nullptr, pol);
0351    return ::log1pl(x);
0352 }
0353 #endif
0354 #else
0355 template <class Policy>
0356 inline float log1p(float x, const Policy& pol)
0357 {
0358    if(x < -1)
0359       return policies::raise_domain_error<float>(
0360          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0361    if(x == -1)
0362       return -policies::raise_overflow_error<float>(
0363          "log1p<%1%>(%1%)", nullptr, pol);
0364    return ::log1p(x);
0365 }
0366 #endif
0367 template <class Policy>
0368 inline double log1p(double x, const Policy& pol)
0369 {
0370    if(x < -1)
0371       return policies::raise_domain_error<double>(
0372          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0373    if(x == -1)
0374       return -policies::raise_overflow_error<double>(
0375          "log1p<%1%>(%1%)", nullptr, pol);
0376    return ::log1p(x);
0377 }
0378 #elif defined(_MSC_VER) && (BOOST_MSVC >= 1400)
0379 //
0380 // You should only enable this branch if you are absolutely sure
0381 // that your compilers optimizer won't mess this code up!!
0382 // Currently tested with VC8 and Intel 9.1.
0383 //
0384 template <class Policy>
0385 inline double log1p(double x, const Policy& pol)
0386 {
0387    if(x < -1)
0388       return policies::raise_domain_error<double>(
0389          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0390    if(x == -1)
0391       return -policies::raise_overflow_error<double>(
0392          "log1p<%1%>(%1%)", nullptr, pol);
0393    double u = 1+x;
0394    if(u == 1.0)
0395       return x;
0396    else
0397       return ::log(u)*(x/(u-1.0));
0398 }
0399 template <class Policy>
0400 inline float log1p(float x, const Policy& pol)
0401 {
0402    return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));
0403 }
0404 #ifndef _WIN32_WCE
0405 //
0406 // For some reason this fails to compile under WinCE...
0407 // Needs more investigation.
0408 //
0409 template <class Policy>
0410 inline long double log1p(long double x, const Policy& pol)
0411 {
0412    if(x < -1)
0413       return policies::raise_domain_error<long double>(
0414          "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
0415    if(x == -1)
0416       return -policies::raise_overflow_error<long double>(
0417          "log1p<%1%>(%1%)", nullptr, pol);
0418    long double u = 1+x;
0419    if(u == 1.0)
0420       return x;
0421    else
0422       return ::logl(u)*(x/(u-1.0));
0423 }
0424 #endif
0425 #endif
0426 
0427 template <class T>
0428 inline typename tools::promote_args<T>::type log1p(T x)
0429 {
0430    return boost::math::log1p(x, policies::policy<>());
0431 }
0432 //
0433 // Compute log(1+x)-x:
0434 //
0435 template <class T, class Policy>
0436 inline typename tools::promote_args<T>::type
0437    log1pmx(T x, const Policy& pol)
0438 {
0439    typedef typename tools::promote_args<T>::type result_type;
0440    BOOST_MATH_STD_USING
0441    static const char* function = "boost::math::log1pmx<%1%>(%1%)";
0442 
0443    if(x < -1)
0444       return policies::raise_domain_error<T>(
0445          function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);
0446    if(x == -1)
0447       return -policies::raise_overflow_error<T>(
0448          function, nullptr, pol);
0449 
0450    result_type a = abs(result_type(x));
0451    if(a > result_type(0.95f))
0452       return log(1 + result_type(x)) - result_type(x);
0453    // Note that without numeric_limits specialisation support,
0454    // epsilon just returns zero, and our "optimisation" will always fail:
0455    if(a < tools::epsilon<result_type>())
0456       return -x * x / 2;
0457    boost::math::detail::log1p_series<T> s(x);
0458    s();
0459    std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0460 
0461    T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
0462 
0463    policies::check_series_iterations<T>(function, max_iter, pol);
0464    return result;
0465 }
0466 
0467 template <class T>
0468 inline typename tools::promote_args<T>::type log1pmx(T x)
0469 {
0470    return log1pmx(x, policies::policy<>());
0471 }
0472 
0473 } // namespace math
0474 } // namespace boost
0475 
0476 #ifdef _MSC_VER
0477 #pragma warning(pop)
0478 #endif
0479 
0480 #endif // BOOST_MATH_LOG1P_INCLUDED
0481 
0482 
0483