You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

534 line
16KB

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