cpp-d1064d
[cross.git] / i686-linux-gnu-4.7 / usr / include / c++ / 4.7 / tr1 / exp_integral.tcc
1 // Special functions -*- C++ -*-
2
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
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 3, or (at your option)
10 // any later version.
11 //
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.
16 //
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 /** @file tr1/exp_integral.tcc
27  *  This is an internal header file, included by other library headers.
28  *  Do not attempt to use it directly. @headername{tr1/cmath}
29  */
30
31 //
32 // ISO C++ 14882 TR1: 5.2  Special functions
33 //
34
35 //  Written by Edward Smith-Rowland based on:
36 //
37 //   (1) Handbook of Mathematical Functions,
38 //       Ed. by Milton Abramowitz and Irene A. Stegun,
39 //       Dover Publications, New-York, Section 5, pp. 228-251.
40 //   (2) The Gnu Scientific Library, http://www.gnu.org/software/gsl
41 //   (3) Numerical Recipes in C, by W. H. Press, S. A. Teukolsky,
42 //       W. T. Vetterling, B. P. Flannery, Cambridge University Press (1992),
43 //       2nd ed, pp. 222-225.
44 //
45
46 #ifndef _GLIBCXX_TR1_EXP_INTEGRAL_TCC
47 #define _GLIBCXX_TR1_EXP_INTEGRAL_TCC 1
48
49 #include "special_function_util.h"
50
51 namespace std _GLIBCXX_VISIBILITY(default)
52 {
53 namespace tr1
54 {
55   // [5.2] Special functions
56
57   // Implementation-space details.
58   namespace __detail
59   {
60   _GLIBCXX_BEGIN_NAMESPACE_VERSION
61
62     template<typename _Tp> _Tp __expint_E1(const _Tp);
63
64     /**
65      *   @brief Return the exponential integral @f$ E_1(x) @f$
66      *          by series summation.  This should be good
67      *          for @f$ x < 1 @f$.
68      * 
69      *   The exponential integral is given by
70      *          \f[
71      *            E_1(x) = \int_{1}^{\infty} \frac{e^{-xt}}{t} dt
72      *          \f]
73      * 
74      *   @param  __x  The argument of the exponential integral function.
75      *   @return  The exponential integral.
76      */
77     template<typename _Tp>
78     _Tp
79     __expint_E1_series(const _Tp __x)
80     {
81       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
82       _Tp __term = _Tp(1);
83       _Tp __esum = _Tp(0);
84       _Tp __osum = _Tp(0);
85       const unsigned int __max_iter = 100;
86       for (unsigned int __i = 1; __i < __max_iter; ++__i)
87         {
88           __term *= - __x / __i;
89           if (std::abs(__term) < __eps)
90             break;
91           if (__term >= _Tp(0))
92             __esum += __term / __i;
93           else
94             __osum += __term / __i;
95         }
96
97       return - __esum - __osum
98              - __numeric_constants<_Tp>::__gamma_e() - std::log(__x);
99     }
100
101
102     /**
103      *   @brief Return the exponential integral @f$ E_1(x) @f$
104      *          by asymptotic expansion.
105      * 
106      *   The exponential integral is given by
107      *          \f[
108      *            E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
109      *          \f]
110      * 
111      *   @param  __x  The argument of the exponential integral function.
112      *   @return  The exponential integral.
113      */
114     template<typename _Tp>
115     _Tp
116     __expint_E1_asymp(const _Tp __x)
117     {
118       _Tp __term = _Tp(1);
119       _Tp __esum = _Tp(1);
120       _Tp __osum = _Tp(0);
121       const unsigned int __max_iter = 1000;
122       for (unsigned int __i = 1; __i < __max_iter; ++__i)
123         {
124           _Tp __prev = __term;
125           __term *= - __i / __x;
126           if (std::abs(__term) > std::abs(__prev))
127             break;
128           if (__term >= _Tp(0))
129             __esum += __term;
130           else
131             __osum += __term;
132         }
133
134       return std::exp(- __x) * (__esum + __osum) / __x;
135     }
136
137
138     /**
139      *   @brief Return the exponential integral @f$ E_n(x) @f$
140      *          by series summation.
141      * 
142      *   The exponential integral is given by
143      *          \f[
144      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
145      *          \f]
146      * 
147      *   @param  __n  The order of the exponential integral function.
148      *   @param  __x  The argument of the exponential integral function.
149      *   @return  The exponential integral.
150      */
151     template<typename _Tp>
152     _Tp
153     __expint_En_series(const unsigned int __n, const _Tp __x)
154     {
155       const unsigned int __max_iter = 100;
156       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
157       const int __nm1 = __n - 1;
158       _Tp __ans = (__nm1 != 0
159                 ? _Tp(1) / __nm1 : -std::log(__x)
160                                    - __numeric_constants<_Tp>::__gamma_e());
161       _Tp __fact = _Tp(1);
162       for (int __i = 1; __i <= __max_iter; ++__i)
163         {
164           __fact *= -__x / _Tp(__i);
165           _Tp __del;
166           if ( __i != __nm1 )
167             __del = -__fact / _Tp(__i - __nm1);
168           else
169             {
170               _Tp __psi = -__numeric_constants<_Tp>::gamma_e();
171               for (int __ii = 1; __ii <= __nm1; ++__ii)
172                 __psi += _Tp(1) / _Tp(__ii);
173               __del = __fact * (__psi - std::log(__x)); 
174             }
175           __ans += __del;
176           if (std::abs(__del) < __eps * std::abs(__ans))
177             return __ans;
178         }
179       std::__throw_runtime_error(__N("Series summation failed "
180                                      "in __expint_En_series."));
181     }
182
183
184     /**
185      *   @brief Return the exponential integral @f$ E_n(x) @f$
186      *          by continued fractions.
187      * 
188      *   The exponential integral is given by
189      *          \f[
190      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
191      *          \f]
192      * 
193      *   @param  __n  The order of the exponential integral function.
194      *   @param  __x  The argument of the exponential integral function.
195      *   @return  The exponential integral.
196      */
197     template<typename _Tp>
198     _Tp
199     __expint_En_cont_frac(const unsigned int __n, const _Tp __x)
200     {
201       const unsigned int __max_iter = 100;
202       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
203       const _Tp __fp_min = std::numeric_limits<_Tp>::min();
204       const int __nm1 = __n - 1;
205       _Tp __b = __x + _Tp(__n);
206       _Tp __c = _Tp(1) / __fp_min;
207       _Tp __d = _Tp(1) / __b;
208       _Tp __h = __d;
209       for ( unsigned int __i = 1; __i <= __max_iter; ++__i )
210         {
211           _Tp __a = -_Tp(__i * (__nm1 + __i));
212           __b += _Tp(2);
213           __d = _Tp(1) / (__a * __d + __b);
214           __c = __b + __a / __c;
215           const _Tp __del = __c * __d;
216           __h *= __del;
217           if (std::abs(__del - _Tp(1)) < __eps)
218             {
219               const _Tp __ans = __h * std::exp(-__x);
220               return __ans;
221             }
222         }
223       std::__throw_runtime_error(__N("Continued fraction failed "
224                                      "in __expint_En_cont_frac."));
225     }
226
227
228     /**
229      *   @brief Return the exponential integral @f$ E_n(x) @f$
230      *          by recursion.  Use upward recursion for @f$ x < n @f$
231      *          and downward recursion (Miller's algorithm) otherwise.
232      * 
233      *   The exponential integral is given by
234      *          \f[
235      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
236      *          \f]
237      * 
238      *   @param  __n  The order of the exponential integral function.
239      *   @param  __x  The argument of the exponential integral function.
240      *   @return  The exponential integral.
241      */
242     template<typename _Tp>
243     _Tp
244     __expint_En_recursion(const unsigned int __n, const _Tp __x)
245     {
246       _Tp __En;
247       _Tp __E1 = __expint_E1(__x);
248       if (__x < _Tp(__n))
249         {
250           //  Forward recursion is stable only for n < x.
251           __En = __E1;
252           for (unsigned int __j = 2; __j < __n; ++__j)
253             __En = (std::exp(-__x) - __x * __En) / _Tp(__j - 1);
254         }
255       else
256         {
257           //  Backward recursion is stable only for n >= x.
258           __En = _Tp(1);
259           const int __N = __n + 20;  //  TODO: Check this starting number.
260           _Tp __save = _Tp(0);
261           for (int __j = __N; __j > 0; --__j)
262             {
263               __En = (std::exp(-__x) - __j * __En) / __x;
264               if (__j == __n)
265                 __save = __En;
266             }
267             _Tp __norm = __En / __E1;
268             __En /= __norm;
269         }
270
271       return __En;
272     }
273
274     /**
275      *   @brief Return the exponential integral @f$ Ei(x) @f$
276      *          by series summation.
277      * 
278      *   The exponential integral is given by
279      *          \f[
280      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
281      *          \f]
282      * 
283      *   @param  __x  The argument of the exponential integral function.
284      *   @return  The exponential integral.
285      */
286     template<typename _Tp>
287     _Tp
288     __expint_Ei_series(const _Tp __x)
289     {
290       _Tp __term = _Tp(1);
291       _Tp __sum = _Tp(0);
292       const unsigned int __max_iter = 1000;
293       for (unsigned int __i = 1; __i < __max_iter; ++__i)
294         {
295           __term *= __x / __i;
296           __sum += __term / __i;
297           if (__term < std::numeric_limits<_Tp>::epsilon() * __sum)
298             break;
299         }
300
301       return __numeric_constants<_Tp>::__gamma_e() + __sum + std::log(__x);
302     }
303
304
305     /**
306      *   @brief Return the exponential integral @f$ Ei(x) @f$
307      *          by asymptotic expansion.
308      * 
309      *   The exponential integral is given by
310      *          \f[
311      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
312      *          \f]
313      * 
314      *   @param  __x  The argument of the exponential integral function.
315      *   @return  The exponential integral.
316      */
317     template<typename _Tp>
318     _Tp
319     __expint_Ei_asymp(const _Tp __x)
320     {
321       _Tp __term = _Tp(1);
322       _Tp __sum = _Tp(1);
323       const unsigned int __max_iter = 1000;
324       for (unsigned int __i = 1; __i < __max_iter; ++__i)
325         {
326           _Tp __prev = __term;
327           __term *= __i / __x;
328           if (__term < std::numeric_limits<_Tp>::epsilon())
329             break;
330           if (__term >= __prev)
331             break;
332           __sum += __term;
333         }
334
335       return std::exp(__x) * __sum / __x;
336     }
337
338
339     /**
340      *   @brief Return the exponential integral @f$ Ei(x) @f$.
341      * 
342      *   The exponential integral is given by
343      *          \f[
344      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
345      *          \f]
346      * 
347      *   @param  __x  The argument of the exponential integral function.
348      *   @return  The exponential integral.
349      */
350     template<typename _Tp>
351     _Tp
352     __expint_Ei(const _Tp __x)
353     {
354       if (__x < _Tp(0))
355         return -__expint_E1(-__x);
356       else if (__x < -std::log(std::numeric_limits<_Tp>::epsilon()))
357         return __expint_Ei_series(__x);
358       else
359         return __expint_Ei_asymp(__x);
360     }
361
362
363     /**
364      *   @brief Return the exponential integral @f$ E_1(x) @f$.
365      * 
366      *   The exponential integral is given by
367      *          \f[
368      *            E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
369      *          \f]
370      * 
371      *   @param  __x  The argument of the exponential integral function.
372      *   @return  The exponential integral.
373      */
374     template<typename _Tp>
375     _Tp
376     __expint_E1(const _Tp __x)
377     {
378       if (__x < _Tp(0))
379         return -__expint_Ei(-__x);
380       else if (__x < _Tp(1))
381         return __expint_E1_series(__x);
382       else if (__x < _Tp(100))  //  TODO: Find a good asymptotic switch point.
383         return __expint_En_cont_frac(1, __x);
384       else
385         return __expint_E1_asymp(__x);
386     }
387
388
389     /**
390      *   @brief Return the exponential integral @f$ E_n(x) @f$
391      *          for large argument.
392      * 
393      *   The exponential integral is given by
394      *          \f[
395      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
396      *          \f]
397      * 
398      *   This is something of an extension.
399      * 
400      *   @param  __n  The order of the exponential integral function.
401      *   @param  __x  The argument of the exponential integral function.
402      *   @return  The exponential integral.
403      */
404     template<typename _Tp>
405     _Tp
406     __expint_asymp(const unsigned int __n, const _Tp __x)
407     {
408       _Tp __term = _Tp(1);
409       _Tp __sum = _Tp(1);
410       for (unsigned int __i = 1; __i <= __n; ++__i)
411         {
412           _Tp __prev = __term;
413           __term *= -(__n - __i + 1) / __x;
414           if (std::abs(__term) > std::abs(__prev))
415             break;
416           __sum += __term;
417         }
418
419       return std::exp(-__x) * __sum / __x;
420     }
421
422
423     /**
424      *   @brief Return the exponential integral @f$ E_n(x) @f$
425      *          for large order.
426      * 
427      *   The exponential integral is given by
428      *          \f[
429      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
430      *          \f]
431      *        
432      *   This is something of an extension.
433      * 
434      *   @param  __n  The order of the exponential integral function.
435      *   @param  __x  The argument of the exponential integral function.
436      *   @return  The exponential integral.
437      */
438     template<typename _Tp>
439     _Tp
440     __expint_large_n(const unsigned int __n, const _Tp __x)
441     {
442       const _Tp __xpn = __x + __n;
443       const _Tp __xpn2 = __xpn * __xpn;
444       _Tp __term = _Tp(1);
445       _Tp __sum = _Tp(1);
446       for (unsigned int __i = 1; __i <= __n; ++__i)
447         {
448           _Tp __prev = __term;
449           __term *= (__n - 2 * (__i - 1) * __x) / __xpn2;
450           if (std::abs(__term) < std::numeric_limits<_Tp>::epsilon())
451             break;
452           __sum += __term;
453         }
454
455       return std::exp(-__x) * __sum / __xpn;
456     }
457
458
459     /**
460      *   @brief Return the exponential integral @f$ E_n(x) @f$.
461      * 
462      *   The exponential integral is given by
463      *          \f[
464      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
465      *          \f]
466      *   This is something of an extension.
467      * 
468      *   @param  __n  The order of the exponential integral function.
469      *   @param  __x  The argument of the exponential integral function.
470      *   @return  The exponential integral.
471      */
472     template<typename _Tp>
473     _Tp
474     __expint(const unsigned int __n, const _Tp __x)
475     {
476       //  Return NaN on NaN input.
477       if (__isnan(__x))
478         return std::numeric_limits<_Tp>::quiet_NaN();
479       else if (__n <= 1 && __x == _Tp(0))
480         return std::numeric_limits<_Tp>::infinity();
481       else
482         {
483           _Tp __E0 = std::exp(__x) / __x;
484           if (__n == 0)
485             return __E0;
486
487           _Tp __E1 = __expint_E1(__x);
488           if (__n == 1)
489             return __E1;
490
491           if (__x == _Tp(0))
492             return _Tp(1) / static_cast<_Tp>(__n - 1);
493
494           _Tp __En = __expint_En_recursion(__n, __x);
495
496           return __En;
497         }
498     }
499
500
501     /**
502      *   @brief Return the exponential integral @f$ Ei(x) @f$.
503      * 
504      *   The exponential integral is given by
505      *   \f[
506      *     Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
507      *   \f]
508      * 
509      *   @param  __x  The argument of the exponential integral function.
510      *   @return  The exponential integral.
511      */
512     template<typename _Tp>
513     inline _Tp
514     __expint(const _Tp __x)
515     {
516       if (__isnan(__x))
517         return std::numeric_limits<_Tp>::quiet_NaN();
518       else
519         return __expint_Ei(__x);
520     }
521
522   _GLIBCXX_END_NAMESPACE_VERSION
523   } // namespace std::tr1::__detail
524 }
525 }
526
527 #endif // _GLIBCXX_TR1_EXP_INTEGRAL_TCC