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_EXPM1_INCLUDED williamr@2: #define BOOST_MATH_EXPM1_INCLUDED williamr@2: williamr@2: #include williamr@2: #include // platform's ::expm1 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 ::exp; using ::fabs; } williamr@2: #endif williamr@2: williamr@2: williamr@2: namespace boost{ namespace math{ williamr@2: williamr@2: namespace detail{ williamr@2: // williamr@2: // Functor expm1_series returns the next term in the Taylor series williamr@2: // x^k / k! williamr@2: // each time that operator() is invoked. williamr@2: // williamr@2: template williamr@2: struct expm1_series williamr@2: { williamr@2: typedef T result_type; williamr@2: williamr@2: expm1_series(T x) williamr@2: : k(0), m_x(x), m_term(1) {} williamr@2: williamr@2: T operator()() williamr@2: { williamr@2: ++k; williamr@2: m_term *= m_x; williamr@2: m_term /= k; williamr@2: return m_term; 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_x; williamr@2: T m_term; williamr@2: expm1_series(const expm1_series&); williamr@2: expm1_series& operator=(const expm1_series&); williamr@2: }; williamr@2: williamr@2: } // namespace williamr@2: williamr@2: // williamr@2: // Algorithm expm1 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. williamr@2: // williamr@2: template williamr@2: T expm1(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: williamr@2: T a = std::fabs(x); williamr@2: if(a > T(0.5L)) williamr@2: return std::exp(x) - T(1); williamr@2: if(a < std::numeric_limits::epsilon()) williamr@2: return x; williamr@2: detail::expm1_series s(x); williamr@2: T result = detail::kahan_sum_series(s, std::numeric_limits::digits + 2); williamr@2: return result; williamr@2: } williamr@2: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) williamr@2: inline float expm1(float z) williamr@2: { williamr@2: return expm1(z); williamr@2: } williamr@2: inline double expm1(double z) williamr@2: { williamr@2: return expm1(z); williamr@2: } williamr@2: inline long double expm1(long double z) williamr@2: { williamr@2: return expm1(z); williamr@2: } williamr@2: #endif williamr@2: williamr@2: #ifdef expm1 williamr@2: # ifndef BOOST_HAS_expm1 williamr@2: # define BOOST_HAS_expm1 williamr@2: # endif williamr@2: # undef expm1 williamr@2: #endif williamr@2: williamr@2: #ifdef BOOST_HAS_EXPM1 williamr@2: # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) williamr@2: inline float expm1(float x){ return ::expm1f(x); } williamr@2: inline long double expm1(long double x){ return ::expm1l(x); } williamr@2: #else williamr@2: inline float expm1(float x){ return ::expm1(x); } williamr@2: #endif williamr@2: inline double expm1(double x){ return ::expm1(x); } williamr@2: #endif williamr@2: williamr@2: } } // namespaces williamr@2: williamr@2: #endif // BOOST_MATH_HYPOT_INCLUDED