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