williamr@2: // (C) Copyright John Maddock 2005. williamr@2: // Use, modification and distribution are subject to the williamr@2: // Boost Software License, Version 1.0. (See accompanying file williamr@2: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) williamr@2: williamr@2: #ifndef BOOST_MATH_LOG1P_INCLUDED williamr@2: #define BOOST_MATH_LOG1P_INCLUDED williamr@2: williamr@2: #include williamr@2: #include // platform's ::log1p williamr@2: #include williamr@2: #include williamr@2: williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: # include williamr@2: #else williamr@2: # include williamr@2: #endif williamr@2: williamr@2: #ifdef BOOST_NO_STDC_NAMESPACE williamr@2: namespace std{ using ::fabs; using ::log; } williamr@2: #endif williamr@2: williamr@2: williamr@2: namespace boost{ namespace math{ williamr@2: williamr@2: namespace detail{ williamr@2: williamr@2: // williamr@2: // Functor log1p_series returns the next term in the Taylor series williamr@2: // pow(-1, k-1)*pow(x, k) / k williamr@2: // each time that operator() is invoked. williamr@2: // williamr@2: template williamr@2: struct log1p_series williamr@2: { williamr@2: typedef T result_type; williamr@2: williamr@2: log1p_series(T x) williamr@2: : k(0), m_mult(-x), m_prod(-1){} williamr@2: williamr@2: T operator()() williamr@2: { williamr@2: m_prod *= m_mult; williamr@2: return m_prod / ++k; williamr@2: } williamr@2: williamr@2: int count()const williamr@2: { williamr@2: return k; williamr@2: } williamr@2: williamr@2: private: williamr@2: int k; williamr@2: const T m_mult; williamr@2: T m_prod; williamr@2: log1p_series(const log1p_series&); williamr@2: log1p_series& operator=(const log1p_series&); williamr@2: }; williamr@2: williamr@2: } // namespace williamr@2: williamr@2: // williamr@2: // Algorithm log1p is part of C99, but is not yet provided by many compilers. williamr@2: // williamr@2: // This version uses a Taylor series expansion for 0.5 > x > epsilon, which may williamr@2: // require up to std::numeric_limits::digits+1 terms to be calculated. It would williamr@2: // be much more efficient to use the equivalence: williamr@2: // log(1+x) == (log(1+x) * x) / ((1-x) - 1) williamr@2: // Unfortunately optimizing compilers make such a mess of this, that it performs williamr@2: // no better than log(1+x): which is to say not very well at all. williamr@2: // williamr@2: template williamr@2: T log1p(T x) williamr@2: { williamr@2: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS williamr@2: BOOST_STATIC_ASSERT(::std::numeric_limits::is_specialized); williamr@2: #else williamr@2: BOOST_ASSERT(std::numeric_limits::is_specialized); williamr@2: #endif williamr@2: T a = std::fabs(x); williamr@2: if(a > T(0.5L)) williamr@2: return std::log(T(1.0) + x); williamr@2: if(a < std::numeric_limits::epsilon()) williamr@2: return x; williamr@2: detail::log1p_series s(x); williamr@2: return detail::kahan_sum_series(s, std::numeric_limits::digits + 2); williamr@2: } williamr@2: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) williamr@2: // these overloads work around a type deduction bug: williamr@2: inline float log1p(float z) williamr@2: { williamr@2: return log1p(z); williamr@2: } williamr@2: inline double log1p(double z) williamr@2: { williamr@2: return log1p(z); williamr@2: } williamr@2: inline long double log1p(long double z) williamr@2: { williamr@2: return log1p(z); williamr@2: } williamr@2: #endif williamr@2: williamr@2: #ifdef log1p williamr@2: # ifndef BOOST_HAS_LOG1P williamr@2: # define BOOST_HAS_LOG1P williamr@2: # endif williamr@2: # undef log1p williamr@2: #endif williamr@2: williamr@2: #ifdef BOOST_HAS_LOG1P williamr@2: # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) williamr@2: inline float log1p(float x){ return ::log1pf(x); } williamr@2: inline long double log1p(long double x){ return ::log1pl(x); } williamr@2: #else williamr@2: inline float log1p(float x){ return ::log1p(x); } williamr@2: #endif williamr@2: inline double log1p(double x){ return ::log1p(x); } williamr@2: #endif williamr@2: williamr@2: } } // namespaces williamr@2: williamr@2: #endif // BOOST_MATH_HYPOT_INCLUDED