1 | // (C) Copyright John Maddock 2005. |
---|
2 | // Use, modification and distribution are subject to the |
---|
3 | // Boost Software License, Version 1.0. (See accompanying file |
---|
4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
5 | |
---|
6 | #ifndef BOOST_MATH_EXPM1_INCLUDED |
---|
7 | #define BOOST_MATH_EXPM1_INCLUDED |
---|
8 | |
---|
9 | #include <cmath> |
---|
10 | #include <math.h> // platform's ::expm1 |
---|
11 | #include <boost/limits.hpp> |
---|
12 | #include <boost/math/special_functions/detail/series.hpp> |
---|
13 | |
---|
14 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
---|
15 | # include <boost/static_assert.hpp> |
---|
16 | #else |
---|
17 | # include <boost/assert.hpp> |
---|
18 | #endif |
---|
19 | |
---|
20 | #ifdef BOOST_NO_STDC_NAMESPACE |
---|
21 | namespace std{ using ::exp; using ::fabs; } |
---|
22 | #endif |
---|
23 | |
---|
24 | |
---|
25 | namespace boost{ namespace math{ |
---|
26 | |
---|
27 | namespace detail{ |
---|
28 | // |
---|
29 | // Functor expm1_series returns the next term in the Taylor series |
---|
30 | // x^k / k! |
---|
31 | // each time that operator() is invoked. |
---|
32 | // |
---|
33 | template <class T> |
---|
34 | struct expm1_series |
---|
35 | { |
---|
36 | typedef T result_type; |
---|
37 | |
---|
38 | expm1_series(T x) |
---|
39 | : k(0), m_x(x), m_term(1) {} |
---|
40 | |
---|
41 | T operator()() |
---|
42 | { |
---|
43 | ++k; |
---|
44 | m_term *= m_x; |
---|
45 | m_term /= k; |
---|
46 | return m_term; |
---|
47 | } |
---|
48 | |
---|
49 | int count()const |
---|
50 | { |
---|
51 | return k; |
---|
52 | } |
---|
53 | |
---|
54 | private: |
---|
55 | int k; |
---|
56 | const T m_x; |
---|
57 | T m_term; |
---|
58 | expm1_series(const expm1_series&); |
---|
59 | expm1_series& operator=(const expm1_series&); |
---|
60 | }; |
---|
61 | |
---|
62 | } // namespace |
---|
63 | |
---|
64 | // |
---|
65 | // Algorithm expm1 is part of C99, but is not yet provided by many compilers. |
---|
66 | // |
---|
67 | // This version uses a Taylor series expansion for 0.5 > |x| > epsilon. |
---|
68 | // |
---|
69 | template <class T> |
---|
70 | T expm1(T x) |
---|
71 | { |
---|
72 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
---|
73 | BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized); |
---|
74 | #else |
---|
75 | BOOST_ASSERT(std::numeric_limits<T>::is_specialized); |
---|
76 | #endif |
---|
77 | |
---|
78 | T a = std::fabs(x); |
---|
79 | if(a > T(0.5L)) |
---|
80 | return std::exp(x) - T(1); |
---|
81 | if(a < std::numeric_limits<T>::epsilon()) |
---|
82 | return x; |
---|
83 | detail::expm1_series<T> s(x); |
---|
84 | T result = detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2); |
---|
85 | return result; |
---|
86 | } |
---|
87 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) |
---|
88 | inline float expm1(float z) |
---|
89 | { |
---|
90 | return expm1<float>(z); |
---|
91 | } |
---|
92 | inline double expm1(double z) |
---|
93 | { |
---|
94 | return expm1<double>(z); |
---|
95 | } |
---|
96 | inline long double expm1(long double z) |
---|
97 | { |
---|
98 | return expm1<long double>(z); |
---|
99 | } |
---|
100 | #endif |
---|
101 | |
---|
102 | #ifdef expm1 |
---|
103 | # ifndef BOOST_HAS_expm1 |
---|
104 | # define BOOST_HAS_expm1 |
---|
105 | # endif |
---|
106 | # undef expm1 |
---|
107 | #endif |
---|
108 | |
---|
109 | #ifdef BOOST_HAS_EXPM1 |
---|
110 | # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) |
---|
111 | inline float expm1(float x){ return ::expm1f(x); } |
---|
112 | inline long double expm1(long double x){ return ::expm1l(x); } |
---|
113 | #else |
---|
114 | inline float expm1(float x){ return ::expm1(x); } |
---|
115 | #endif |
---|
116 | inline double expm1(double x){ return ::expm1(x); } |
---|
117 | #endif |
---|
118 | |
---|
119 | } } // namespaces |
---|
120 | |
---|
121 | #endif // BOOST_MATH_HYPOT_INCLUDED |
---|