1 // Special functions -*- C++ -*-
3 // Copyright (C) 2006-2007
4 // Free Software Foundation, Inc.
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING. If not, write to the Free
19 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction. Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License. This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
31 /** @file tr1/exp_integral.tcc
32 * This is an internal header file, included by other library headers.
33 * You should not attempt to use it directly.
37 // ISO C++ 14882 TR1: 5.2 Special functions
40 // Written by Edward Smith-Rowland based on:
42 // (1) Handbook of Mathematical Functions,
43 // Ed. by Milton Abramowitz and Irene A. Stegun,
44 // Dover Publications, New-York, Section 5, pp. 228-251.
45 // (2) The Gnu Scientific Library, http://www.gnu.org/software/gsl
46 // (3) Numerical Recipes in C, by W. H. Press, S. A. Teukolsky,
47 // W. T. Vetterling, B. P. Flannery, Cambridge University Press (1992),
48 // 2nd ed, pp. 222-225.
51 #ifndef _GLIBCXX_TR1_EXP_INTEGRAL_TCC
52 #define _GLIBCXX_TR1_EXP_INTEGRAL_TCC 1
54 #include "special_function_util.h"
61 // [5.2] Special functions
64 * @ingroup tr1_math_spec_func
69 // Implementation-space details.
75 * @brief Return the exponential integral @f$ E_1(x) @f$
76 * by series summation. This should be good
79 * The exponential integral is given by
81 * E_1(x) = \int_{1}^{\infty} \frac{e^{-xt}}{t} dt
84 * @param __x The argument of the exponential integral function.
85 * @return The exponential integral.
87 template<typename _Tp>
89 __expint_E1_series(const _Tp __x)
91 const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
95 const unsigned int __max_iter = 100;
96 for (unsigned int __i = 1; __i < __max_iter; ++__i)
98 __term *= - __x / __i;
99 if (std::abs(__term) < __eps)
101 if (__term >= _Tp(0))
102 __esum += __term / __i;
104 __osum += __term / __i;
107 return - __esum - __osum
108 - __numeric_constants<_Tp>::__gamma_e() - std::log(__x);
113 * @brief Return the exponential integral @f$ E_1(x) @f$
114 * by asymptotic expansion.
116 * The exponential integral is given by
118 * E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
121 * @param __x The argument of the exponential integral function.
122 * @return The exponential integral.
124 template<typename _Tp>
126 __expint_E1_asymp(const _Tp __x)
131 const unsigned int __max_iter = 1000;
132 for (unsigned int __i = 1; __i < __max_iter; ++__i)
135 __term *= - __i / __x;
136 if (std::abs(__term) > std::abs(__prev))
138 if (__term >= _Tp(0))
144 return std::exp(- __x) * (__esum + __osum) / __x;
149 * @brief Return the exponential integral @f$ E_n(x) @f$
150 * by series summation.
152 * The exponential integral is given by
154 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
157 * @param __n The order of the exponential integral function.
158 * @param __x The argument of the exponential integral function.
159 * @return The exponential integral.
161 template<typename _Tp>
163 __expint_En_series(const unsigned int __n, const _Tp __x)
165 const unsigned int __max_iter = 100;
166 const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
167 const int __nm1 = __n - 1;
168 _Tp __ans = (__nm1 != 0
169 ? _Tp(1) / __nm1 : -std::log(__x)
170 - __numeric_constants<_Tp>::__gamma_e());
172 for (int __i = 1; __i <= __max_iter; ++__i)
174 __fact *= -__x / _Tp(__i);
177 __del = -__fact / _Tp(__i - __nm1);
180 _Tp __psi = -_TR1_GAMMA_TCC;
181 for (int __ii = 1; __ii <= __nm1; ++__ii)
182 __psi += _Tp(1) / _Tp(__ii);
183 __del = __fact * (__psi - std::log(__x));
186 if (std::abs(__del) < __eps * std::abs(__ans))
189 std::__throw_runtime_error(__N("Series summation failed "
190 "in __expint_En_series."));
195 * @brief Return the exponential integral @f$ E_n(x) @f$
196 * by continued fractions.
198 * The exponential integral is given by
200 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
203 * @param __n The order of the exponential integral function.
204 * @param __x The argument of the exponential integral function.
205 * @return The exponential integral.
207 template<typename _Tp>
209 __expint_En_cont_frac(const unsigned int __n, const _Tp __x)
211 const unsigned int __max_iter = 100;
212 const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
213 const _Tp __fp_min = std::numeric_limits<_Tp>::min();
214 const int __nm1 = __n - 1;
215 _Tp __b = __x + _Tp(__n);
216 _Tp __c = _Tp(1) / __fp_min;
217 _Tp __d = _Tp(1) / __b;
219 for ( unsigned int __i = 1; __i <= __max_iter; ++__i )
221 _Tp __a = -_Tp(__i * (__nm1 + __i));
223 __d = _Tp(1) / (__a * __d + __b);
224 __c = __b + __a / __c;
225 const _Tp __del = __c * __d;
227 if (std::abs(__del - _Tp(1)) < __eps)
229 const _Tp __ans = __h * std::exp(-__x);
233 std::__throw_runtime_error(__N("Continued fraction failed "
234 "in __expint_En_cont_frac."));
239 * @brief Return the exponential integral @f$ E_n(x) @f$
240 * by recursion. Use upward recursion for @f$ x < n @f$
241 * and downward recursion (Miller's algorithm) otherwise.
243 * The exponential integral is given by
245 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
248 * @param __n The order of the exponential integral function.
249 * @param __x The argument of the exponential integral function.
250 * @return The exponential integral.
252 template<typename _Tp>
254 __expint_En_recursion(const unsigned int __n, const _Tp __x)
257 _Tp __E1 = __expint_E1(__x);
260 // Forward recursion is stable only for n < x.
262 for (unsigned int __j = 2; __j < __n; ++__j)
263 __En = (std::exp(-__x) - __x * __En) / _Tp(__j - 1);
267 // Backward recursion is stable only for n >= x.
269 const int __N = __n + 20; // TODO: Check this starting number.
271 for (int __j = __N; __j > 0; --__j)
273 __En = (std::exp(-__x) - __j * __En) / __x;
277 _Tp __norm = __En / __E1;
285 * @brief Return the exponential integral @f$ Ei(x) @f$
286 * by series summation.
288 * The exponential integral is given by
290 * Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
293 * @param __x The argument of the exponential integral function.
294 * @return The exponential integral.
296 template<typename _Tp>
298 __expint_Ei_series(const _Tp __x)
302 const unsigned int __max_iter = 1000;
303 for (unsigned int __i = 1; __i < __max_iter; ++__i)
306 __sum += __term / __i;
307 if (__term < std::numeric_limits<_Tp>::epsilon() * __sum)
311 return __numeric_constants<_Tp>::__gamma_e() + __sum + std::log(__x);
316 * @brief Return the exponential integral @f$ Ei(x) @f$
317 * by asymptotic expansion.
319 * The exponential integral is given by
321 * Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
324 * @param __x The argument of the exponential integral function.
325 * @return The exponential integral.
327 template<typename _Tp>
329 __expint_Ei_asymp(const _Tp __x)
333 const unsigned int __max_iter = 1000;
334 for (unsigned int __i = 1; __i < __max_iter; ++__i)
338 if (__term < std::numeric_limits<_Tp>::epsilon())
340 if (__term >= __prev)
345 return std::exp(__x) * __sum / __x;
350 * @brief Return the exponential integral @f$ Ei(x) @f$.
352 * The exponential integral is given by
354 * Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
357 * @param __x The argument of the exponential integral function.
358 * @return The exponential integral.
360 template<typename _Tp>
362 __expint_Ei(const _Tp __x)
365 return -__expint_E1(-__x);
366 else if (__x < -std::log(std::numeric_limits<_Tp>::epsilon()))
367 return __expint_Ei_series(__x);
369 return __expint_Ei_asymp(__x);
374 * @brief Return the exponential integral @f$ E_1(x) @f$.
376 * The exponential integral is given by
378 * E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
381 * @param __x The argument of the exponential integral function.
382 * @return The exponential integral.
384 template<typename _Tp>
386 __expint_E1(const _Tp __x)
389 return -__expint_Ei(-__x);
390 else if (__x < _Tp(1))
391 return __expint_E1_series(__x);
392 else if (__x < _Tp(100)) // TODO: Find a good asymptotic switch point.
393 return __expint_En_cont_frac(1, __x);
395 return __expint_E1_asymp(__x);
400 * @brief Return the exponential integral @f$ E_n(x) @f$
401 * for large argument.
403 * The exponential integral is given by
405 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
408 * This is something of an extension.
410 * @param __n The order of the exponential integral function.
411 * @param __x The argument of the exponential integral function.
412 * @return The exponential integral.
414 template<typename _Tp>
416 __expint_asymp(const unsigned int __n, const _Tp __x)
420 for (unsigned int __i = 1; __i <= __n; ++__i)
423 __term *= -(__n - __i + 1) / __x;
424 if (std::abs(__term) > std::abs(__prev))
429 return std::exp(-__x) * __sum / __x;
434 * @brief Return the exponential integral @f$ E_n(x) @f$
437 * The exponential integral is given by
439 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
442 * This is something of an extension.
444 * @param __n The order of the exponential integral function.
445 * @param __x The argument of the exponential integral function.
446 * @return The exponential integral.
448 template<typename _Tp>
450 __expint_large_n(const unsigned int __n, const _Tp __x)
452 const _Tp __xpn = __x + __n;
453 const _Tp __xpn2 = __xpn * __xpn;
456 for (unsigned int __i = 1; __i <= __n; ++__i)
459 __term *= (__n - 2 * (__i - 1) * __x) / __xpn2;
460 if (std::abs(__term) < std::numeric_limits<_Tp>::epsilon())
465 return std::exp(-__x) * __sum / __xpn;
470 * @brief Return the exponential integral @f$ E_n(x) @f$.
472 * The exponential integral is given by
474 * E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
476 * This is something of an extension.
478 * @param __n The order of the exponential integral function.
479 * @param __x The argument of the exponential integral function.
480 * @return The exponential integral.
482 template<typename _Tp>
484 __expint(const unsigned int __n, const _Tp __x)
486 // Return NaN on NaN input.
488 return std::numeric_limits<_Tp>::quiet_NaN();
489 else if (__n <= 1 && __x == _Tp(0))
490 return std::numeric_limits<_Tp>::infinity();
493 _Tp __E0 = std::exp(__x) / __x;
497 _Tp __E1 = __expint_E1(__x);
502 return _Tp(1) / static_cast<_Tp>(__n - 1);
504 _Tp __En = __expint_En_recursion(__n, __x);
512 * @brief Return the exponential integral @f$ Ei(x) @f$.
514 * The exponential integral is given by
516 * Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
519 * @param __x The argument of the exponential integral function.
520 * @return The exponential integral.
522 template<typename _Tp>
524 __expint(const _Tp __x)
527 return std::numeric_limits<_Tp>::quiet_NaN();
529 return __expint_Ei(__x);
532 } // namespace std::tr1::__detail
534 /* @} */ // group tr1_math_spec_func
539 #endif // _GLIBCXX_TR1_EXP_INTEGRAL_TCC