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