Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // Special functions -*- C++ -*-
  2.  
  3. // Copyright (C) 2006-2015 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 "special_function_util.h"
  49.  
  50. namespace std _GLIBCXX_VISIBILITY(default)
  51. {
  52. namespace tr1
  53. {
  54.   // [5.2] Special functions
  55.  
  56.   // Implementation-space details.
  57.   namespace __detail
  58.   {
  59.   _GLIBCXX_BEGIN_NAMESPACE_VERSION
  60.  
  61.     template<typename _Tp> _Tp __expint_E1(_Tp);
  62.  
  63.     /**
  64.      *   @brief Return the exponential integral @f$ E_1(x) @f$
  65.      *          by series summation.  This should be good
  66.      *          for @f$ x < 1 @f$.
  67.      *
  68.      *   The exponential integral is given by
  69.      *          \f[
  70.      *            E_1(x) = \int_{1}^{\infty} \frac{e^{-xt}}{t} dt
  71.      *          \f]
  72.      *
  73.      *   @param  __x  The argument of the exponential integral function.
  74.      *   @return  The exponential integral.
  75.      */
  76.     template<typename _Tp>
  77.     _Tp
  78.     __expint_E1_series(_Tp __x)
  79.     {
  80.       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
  81.       _Tp __term = _Tp(1);
  82.       _Tp __esum = _Tp(0);
  83.       _Tp __osum = _Tp(0);
  84.       const unsigned int __max_iter = 100;
  85.       for (unsigned int __i = 1; __i < __max_iter; ++__i)
  86.         {
  87.           __term *= - __x / __i;
  88.           if (std::abs(__term) < __eps)
  89.             break;
  90.           if (__term >= _Tp(0))
  91.             __esum += __term / __i;
  92.           else
  93.             __osum += __term / __i;
  94.         }
  95.  
  96.       return - __esum - __osum
  97.              - __numeric_constants<_Tp>::__gamma_e() - std::log(__x);
  98.     }
  99.  
  100.  
  101.     /**
  102.      *   @brief Return the exponential integral @f$ E_1(x) @f$
  103.      *          by asymptotic expansion.
  104.      *
  105.      *   The exponential integral is given by
  106.      *          \f[
  107.      *            E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
  108.      *          \f]
  109.      *
  110.      *   @param  __x  The argument of the exponential integral function.
  111.      *   @return  The exponential integral.
  112.      */
  113.     template<typename _Tp>
  114.     _Tp
  115.     __expint_E1_asymp(_Tp __x)
  116.     {
  117.       _Tp __term = _Tp(1);
  118.       _Tp __esum = _Tp(1);
  119.       _Tp __osum = _Tp(0);
  120.       const unsigned int __max_iter = 1000;
  121.       for (unsigned int __i = 1; __i < __max_iter; ++__i)
  122.         {
  123.           _Tp __prev = __term;
  124.           __term *= - __i / __x;
  125.           if (std::abs(__term) > std::abs(__prev))
  126.             break;
  127.           if (__term >= _Tp(0))
  128.             __esum += __term;
  129.           else
  130.             __osum += __term;
  131.         }
  132.  
  133.       return std::exp(- __x) * (__esum + __osum) / __x;
  134.     }
  135.  
  136.  
  137.     /**
  138.      *   @brief Return the exponential integral @f$ E_n(x) @f$
  139.      *          by series summation.
  140.      *
  141.      *   The exponential integral is given by
  142.      *          \f[
  143.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  144.      *          \f]
  145.      *
  146.      *   @param  __n  The order of the exponential integral function.
  147.      *   @param  __x  The argument of the exponential integral function.
  148.      *   @return  The exponential integral.
  149.      */
  150.     template<typename _Tp>
  151.     _Tp
  152.     __expint_En_series(unsigned int __n, _Tp __x)
  153.     {
  154.       const unsigned int __max_iter = 100;
  155.       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
  156.       const int __nm1 = __n - 1;
  157.       _Tp __ans = (__nm1 != 0
  158.                 ? _Tp(1) / __nm1 : -std::log(__x)
  159.                                    - __numeric_constants<_Tp>::__gamma_e());
  160.       _Tp __fact = _Tp(1);
  161.       for (int __i = 1; __i <= __max_iter; ++__i)
  162.         {
  163.           __fact *= -__x / _Tp(__i);
  164.           _Tp __del;
  165.           if ( __i != __nm1 )
  166.             __del = -__fact / _Tp(__i - __nm1);
  167.           else
  168.             {
  169.               _Tp __psi = -__numeric_constants<_Tp>::gamma_e();
  170.               for (int __ii = 1; __ii <= __nm1; ++__ii)
  171.                 __psi += _Tp(1) / _Tp(__ii);
  172.               __del = __fact * (__psi - std::log(__x));
  173.             }
  174.           __ans += __del;
  175.           if (std::abs(__del) < __eps * std::abs(__ans))
  176.             return __ans;
  177.         }
  178.       std::__throw_runtime_error(__N("Series summation failed "
  179.                                      "in __expint_En_series."));
  180.     }
  181.  
  182.  
  183.     /**
  184.      *   @brief Return the exponential integral @f$ E_n(x) @f$
  185.      *          by continued fractions.
  186.      *
  187.      *   The exponential integral is given by
  188.      *          \f[
  189.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  190.      *          \f]
  191.      *
  192.      *   @param  __n  The order of the exponential integral function.
  193.      *   @param  __x  The argument of the exponential integral function.
  194.      *   @return  The exponential integral.
  195.      */
  196.     template<typename _Tp>
  197.     _Tp
  198.     __expint_En_cont_frac(unsigned int __n, _Tp __x)
  199.     {
  200.       const unsigned int __max_iter = 100;
  201.       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
  202.       const _Tp __fp_min = std::numeric_limits<_Tp>::min();
  203.       const int __nm1 = __n - 1;
  204.       _Tp __b = __x + _Tp(__n);
  205.       _Tp __c = _Tp(1) / __fp_min;
  206.       _Tp __d = _Tp(1) / __b;
  207.       _Tp __h = __d;
  208.       for ( unsigned int __i = 1; __i <= __max_iter; ++__i )
  209.         {
  210.           _Tp __a = -_Tp(__i * (__nm1 + __i));
  211.           __b += _Tp(2);
  212.           __d = _Tp(1) / (__a * __d + __b);
  213.           __c = __b + __a / __c;
  214.           const _Tp __del = __c * __d;
  215.           __h *= __del;
  216.           if (std::abs(__del - _Tp(1)) < __eps)
  217.             {
  218.               const _Tp __ans = __h * std::exp(-__x);
  219.               return __ans;
  220.             }
  221.         }
  222.       std::__throw_runtime_error(__N("Continued fraction failed "
  223.                                      "in __expint_En_cont_frac."));
  224.     }
  225.  
  226.  
  227.     /**
  228.      *   @brief Return the exponential integral @f$ E_n(x) @f$
  229.      *          by recursion.  Use upward recursion for @f$ x < n @f$
  230.      *          and downward recursion (Miller's algorithm) otherwise.
  231.      *
  232.      *   The exponential integral is given by
  233.      *          \f[
  234.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  235.      *          \f]
  236.      *
  237.      *   @param  __n  The order of the exponential integral function.
  238.      *   @param  __x  The argument of the exponential integral function.
  239.      *   @return  The exponential integral.
  240.      */
  241.     template<typename _Tp>
  242.     _Tp
  243.     __expint_En_recursion(unsigned int __n, _Tp __x)
  244.     {
  245.       _Tp __En;
  246.       _Tp __E1 = __expint_E1(__x);
  247.       if (__x < _Tp(__n))
  248.         {
  249.           //  Forward recursion is stable only for n < x.
  250.           __En = __E1;
  251.           for (unsigned int __j = 2; __j < __n; ++__j)
  252.             __En = (std::exp(-__x) - __x * __En) / _Tp(__j - 1);
  253.         }
  254.       else
  255.         {
  256.           //  Backward recursion is stable only for n >= x.
  257.           __En = _Tp(1);
  258.           const int __N = __n + 20;  //  TODO: Check this starting number.
  259.           _Tp __save = _Tp(0);
  260.           for (int __j = __N; __j > 0; --__j)
  261.             {
  262.               __En = (std::exp(-__x) - __j * __En) / __x;
  263.               if (__j == __n)
  264.                 __save = __En;
  265.             }
  266.             _Tp __norm = __En / __E1;
  267.             __En /= __norm;
  268.         }
  269.  
  270.       return __En;
  271.     }
  272.  
  273.     /**
  274.      *   @brief Return the exponential integral @f$ Ei(x) @f$
  275.      *          by series summation.
  276.      *
  277.      *   The exponential integral is given by
  278.      *          \f[
  279.      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
  280.      *          \f]
  281.      *
  282.      *   @param  __x  The argument of the exponential integral function.
  283.      *   @return  The exponential integral.
  284.      */
  285.     template<typename _Tp>
  286.     _Tp
  287.     __expint_Ei_series(_Tp __x)
  288.     {
  289.       _Tp __term = _Tp(1);
  290.       _Tp __sum = _Tp(0);
  291.       const unsigned int __max_iter = 1000;
  292.       for (unsigned int __i = 1; __i < __max_iter; ++__i)
  293.         {
  294.           __term *= __x / __i;
  295.           __sum += __term / __i;
  296.           if (__term < std::numeric_limits<_Tp>::epsilon() * __sum)
  297.             break;
  298.         }
  299.  
  300.       return __numeric_constants<_Tp>::__gamma_e() + __sum + std::log(__x);
  301.     }
  302.  
  303.  
  304.     /**
  305.      *   @brief Return the exponential integral @f$ Ei(x) @f$
  306.      *          by asymptotic expansion.
  307.      *
  308.      *   The exponential integral is given by
  309.      *          \f[
  310.      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
  311.      *          \f]
  312.      *
  313.      *   @param  __x  The argument of the exponential integral function.
  314.      *   @return  The exponential integral.
  315.      */
  316.     template<typename _Tp>
  317.     _Tp
  318.     __expint_Ei_asymp(_Tp __x)
  319.     {
  320.       _Tp __term = _Tp(1);
  321.       _Tp __sum = _Tp(1);
  322.       const unsigned int __max_iter = 1000;
  323.       for (unsigned int __i = 1; __i < __max_iter; ++__i)
  324.         {
  325.           _Tp __prev = __term;
  326.           __term *= __i / __x;
  327.           if (__term < std::numeric_limits<_Tp>::epsilon())
  328.             break;
  329.           if (__term >= __prev)
  330.             break;
  331.           __sum += __term;
  332.         }
  333.  
  334.       return std::exp(__x) * __sum / __x;
  335.     }
  336.  
  337.  
  338.     /**
  339.      *   @brief Return the exponential integral @f$ Ei(x) @f$.
  340.      *
  341.      *   The exponential integral is given by
  342.      *          \f[
  343.      *            Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
  344.      *          \f]
  345.      *
  346.      *   @param  __x  The argument of the exponential integral function.
  347.      *   @return  The exponential integral.
  348.      */
  349.     template<typename _Tp>
  350.     _Tp
  351.     __expint_Ei(_Tp __x)
  352.     {
  353.       if (__x < _Tp(0))
  354.         return -__expint_E1(-__x);
  355.       else if (__x < -std::log(std::numeric_limits<_Tp>::epsilon()))
  356.         return __expint_Ei_series(__x);
  357.       else
  358.         return __expint_Ei_asymp(__x);
  359.     }
  360.  
  361.  
  362.     /**
  363.      *   @brief Return the exponential integral @f$ E_1(x) @f$.
  364.      *
  365.      *   The exponential integral is given by
  366.      *          \f[
  367.      *            E_1(x) = \int_{1}^\infty \frac{e^{-xt}}{t} dt
  368.      *          \f]
  369.      *
  370.      *   @param  __x  The argument of the exponential integral function.
  371.      *   @return  The exponential integral.
  372.      */
  373.     template<typename _Tp>
  374.     _Tp
  375.     __expint_E1(_Tp __x)
  376.     {
  377.       if (__x < _Tp(0))
  378.         return -__expint_Ei(-__x);
  379.       else if (__x < _Tp(1))
  380.         return __expint_E1_series(__x);
  381.       else if (__x < _Tp(100))  //  TODO: Find a good asymptotic switch point.
  382.         return __expint_En_cont_frac(1, __x);
  383.       else
  384.         return __expint_E1_asymp(__x);
  385.     }
  386.  
  387.  
  388.     /**
  389.      *   @brief Return the exponential integral @f$ E_n(x) @f$
  390.      *          for large argument.
  391.      *
  392.      *   The exponential integral is given by
  393.      *          \f[
  394.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  395.      *          \f]
  396.      *
  397.      *   This is something of an extension.
  398.      *
  399.      *   @param  __n  The order of the exponential integral function.
  400.      *   @param  __x  The argument of the exponential integral function.
  401.      *   @return  The exponential integral.
  402.      */
  403.     template<typename _Tp>
  404.     _Tp
  405.     __expint_asymp(unsigned int __n, _Tp __x)
  406.     {
  407.       _Tp __term = _Tp(1);
  408.       _Tp __sum = _Tp(1);
  409.       for (unsigned int __i = 1; __i <= __n; ++__i)
  410.         {
  411.           _Tp __prev = __term;
  412.           __term *= -(__n - __i + 1) / __x;
  413.           if (std::abs(__term) > std::abs(__prev))
  414.             break;
  415.           __sum += __term;
  416.         }
  417.  
  418.       return std::exp(-__x) * __sum / __x;
  419.     }
  420.  
  421.  
  422.     /**
  423.      *   @brief Return the exponential integral @f$ E_n(x) @f$
  424.      *          for large order.
  425.      *
  426.      *   The exponential integral is given by
  427.      *          \f[
  428.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  429.      *          \f]
  430.      *        
  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_large_n(unsigned int __n, _Tp __x)
  440.     {
  441.       const _Tp __xpn = __x + __n;
  442.       const _Tp __xpn2 = __xpn * __xpn;
  443.       _Tp __term = _Tp(1);
  444.       _Tp __sum = _Tp(1);
  445.       for (unsigned int __i = 1; __i <= __n; ++__i)
  446.         {
  447.           _Tp __prev = __term;
  448.           __term *= (__n - 2 * (__i - 1) * __x) / __xpn2;
  449.           if (std::abs(__term) < std::numeric_limits<_Tp>::epsilon())
  450.             break;
  451.           __sum += __term;
  452.         }
  453.  
  454.       return std::exp(-__x) * __sum / __xpn;
  455.     }
  456.  
  457.  
  458.     /**
  459.      *   @brief Return the exponential integral @f$ E_n(x) @f$.
  460.      *
  461.      *   The exponential integral is given by
  462.      *          \f[
  463.      *            E_n(x) = \int_{1}^\infty \frac{e^{-xt}}{t^n} dt
  464.      *          \f]
  465.      *   This is something of an extension.
  466.      *
  467.      *   @param  __n  The order of the exponential integral function.
  468.      *   @param  __x  The argument of the exponential integral function.
  469.      *   @return  The exponential integral.
  470.      */
  471.     template<typename _Tp>
  472.     _Tp
  473.     __expint(unsigned int __n, _Tp __x)
  474.     {
  475.       //  Return NaN on NaN input.
  476.       if (__isnan(__x))
  477.         return std::numeric_limits<_Tp>::quiet_NaN();
  478.       else if (__n <= 1 && __x == _Tp(0))
  479.         return std::numeric_limits<_Tp>::infinity();
  480.       else
  481.         {
  482.           _Tp __E0 = std::exp(__x) / __x;
  483.           if (__n == 0)
  484.             return __E0;
  485.  
  486.           _Tp __E1 = __expint_E1(__x);
  487.           if (__n == 1)
  488.             return __E1;
  489.  
  490.           if (__x == _Tp(0))
  491.             return _Tp(1) / static_cast<_Tp>(__n - 1);
  492.  
  493.           _Tp __En = __expint_En_recursion(__n, __x);
  494.  
  495.           return __En;
  496.         }
  497.     }
  498.  
  499.  
  500.     /**
  501.      *   @brief Return the exponential integral @f$ Ei(x) @f$.
  502.      *
  503.      *   The exponential integral is given by
  504.      *   \f[
  505.      *     Ei(x) = -\int_{-x}^\infty \frac{e^t}{t} dt
  506.      *   \f]
  507.      *
  508.      *   @param  __x  The argument of the exponential integral function.
  509.      *   @return  The exponential integral.
  510.      */
  511.     template<typename _Tp>
  512.     inline _Tp
  513.     __expint(_Tp __x)
  514.     {
  515.       if (__isnan(__x))
  516.         return std::numeric_limits<_Tp>::quiet_NaN();
  517.       else
  518.         return __expint_Ei(__x);
  519.     }
  520.  
  521.   _GLIBCXX_END_NAMESPACE_VERSION
  522.   } // namespace std::tr1::__detail
  523. }
  524. }
  525.  
  526. #endif // _GLIBCXX_TR1_EXP_INTEGRAL_TCC
  527.