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_LOG1P_INCLUDED |
---|
7 | #define BOOST_MATH_LOG1P_INCLUDED |
---|
8 | |
---|
9 | #include <cmath> |
---|
10 | #include <math.h> // platform's ::log1p |
---|
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 ::fabs; using ::log; } |
---|
22 | #endif |
---|
23 | |
---|
24 | |
---|
25 | namespace boost{ namespace math{ |
---|
26 | |
---|
27 | namespace detail{ |
---|
28 | |
---|
29 | // |
---|
30 | // Functor log1p_series returns the next term in the Taylor series |
---|
31 | // pow(-1, k-1)*pow(x, k) / k |
---|
32 | // each time that operator() is invoked. |
---|
33 | // |
---|
34 | template <class T> |
---|
35 | struct log1p_series |
---|
36 | { |
---|
37 | typedef T result_type; |
---|
38 | |
---|
39 | log1p_series(T x) |
---|
40 | : k(0), m_mult(-x), m_prod(-1){} |
---|
41 | |
---|
42 | T operator()() |
---|
43 | { |
---|
44 | m_prod *= m_mult; |
---|
45 | return m_prod / ++k; |
---|
46 | } |
---|
47 | |
---|
48 | int count()const |
---|
49 | { |
---|
50 | return k; |
---|
51 | } |
---|
52 | |
---|
53 | private: |
---|
54 | int k; |
---|
55 | const T m_mult; |
---|
56 | T m_prod; |
---|
57 | log1p_series(const log1p_series&); |
---|
58 | log1p_series& operator=(const log1p_series&); |
---|
59 | }; |
---|
60 | |
---|
61 | } // namespace |
---|
62 | |
---|
63 | // |
---|
64 | // Algorithm log1p is part of C99, but is not yet provided by many compilers. |
---|
65 | // |
---|
66 | // This version uses a Taylor series expansion for 0.5 > x > epsilon, which may |
---|
67 | // require up to std::numeric_limits<T>::digits+1 terms to be calculated. It would |
---|
68 | // be much more efficient to use the equivalence: |
---|
69 | // log(1+x) == (log(1+x) * x) / ((1-x) - 1) |
---|
70 | // Unfortunately optimizing compilers make such a mess of this, that it performs |
---|
71 | // no better than log(1+x): which is to say not very well at all. |
---|
72 | // |
---|
73 | template <class T> |
---|
74 | T log1p(T x) |
---|
75 | { |
---|
76 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
---|
77 | BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized); |
---|
78 | #else |
---|
79 | BOOST_ASSERT(std::numeric_limits<T>::is_specialized); |
---|
80 | #endif |
---|
81 | T a = std::fabs(x); |
---|
82 | if(a > T(0.5L)) |
---|
83 | return std::log(T(1.0) + x); |
---|
84 | if(a < std::numeric_limits<T>::epsilon()) |
---|
85 | return x; |
---|
86 | detail::log1p_series<T> s(x); |
---|
87 | return detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2); |
---|
88 | } |
---|
89 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) |
---|
90 | // these overloads work around a type deduction bug: |
---|
91 | inline float log1p(float z) |
---|
92 | { |
---|
93 | return log1p<float>(z); |
---|
94 | } |
---|
95 | inline double log1p(double z) |
---|
96 | { |
---|
97 | return log1p<double>(z); |
---|
98 | } |
---|
99 | inline long double log1p(long double z) |
---|
100 | { |
---|
101 | return log1p<long double>(z); |
---|
102 | } |
---|
103 | #endif |
---|
104 | |
---|
105 | #ifdef log1p |
---|
106 | # ifndef BOOST_HAS_LOG1P |
---|
107 | # define BOOST_HAS_LOG1P |
---|
108 | # endif |
---|
109 | # undef log1p |
---|
110 | #endif |
---|
111 | |
---|
112 | #ifdef BOOST_HAS_LOG1P |
---|
113 | # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) |
---|
114 | inline float log1p(float x){ return ::log1pf(x); } |
---|
115 | inline long double log1p(long double x){ return ::log1pl(x); } |
---|
116 | #else |
---|
117 | inline float log1p(float x){ return ::log1p(x); } |
---|
118 | #endif |
---|
119 | inline double log1p(double x){ return ::log1p(x); } |
---|
120 | #endif |
---|
121 | |
---|
122 | } } // namespaces |
---|
123 | |
---|
124 | #endif // BOOST_MATH_HYPOT_INCLUDED |
---|