Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // Special functions -*- C++ -*-
  2.  
  3. // Copyright (C) 2006-2013 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/poly_laguerre.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. //   (1) Handbook of Mathematical Functions,
  36. //       Ed. Milton Abramowitz and Irene A. Stegun,
  37. //       Dover Publications,
  38. //       Section 13, pp. 509-510, Section 22 pp. 773-802
  39. //   (2) The Gnu Scientific Library, http://www.gnu.org/software/gsl
  40.  
  41. #ifndef _GLIBCXX_TR1_POLY_LAGUERRE_TCC
  42. #define _GLIBCXX_TR1_POLY_LAGUERRE_TCC 1
  43.  
  44. namespace std _GLIBCXX_VISIBILITY(default)
  45. {
  46. namespace tr1
  47. {
  48.   // [5.2] Special functions
  49.  
  50.   // Implementation-space details.
  51.   namespace __detail
  52.   {
  53.   _GLIBCXX_BEGIN_NAMESPACE_VERSION
  54.  
  55.     /**
  56.      *   @brief This routine returns the associated Laguerre polynomial
  57.      *          of order @f$ n @f$, degree @f$ \alpha @f$ for large n.
  58.      *   Abramowitz & Stegun, 13.5.21
  59.      *
  60.      *   @param __n The order of the Laguerre function.
  61.      *   @param __alpha The degree of the Laguerre function.
  62.      *   @param __x The argument of the Laguerre function.
  63.      *   @return The value of the Laguerre function of order n,
  64.      *           degree @f$ \alpha @f$, and argument x.
  65.      *
  66.      *  This is from the GNU Scientific Library.
  67.      */
  68.     template<typename _Tpa, typename _Tp>
  69.     _Tp
  70.     __poly_laguerre_large_n(unsigned __n, _Tpa __alpha1, _Tp __x)
  71.     {
  72.       const _Tp __a = -_Tp(__n);
  73.       const _Tp __b = _Tp(__alpha1) + _Tp(1);
  74.       const _Tp __eta = _Tp(2) * __b - _Tp(4) * __a;
  75.       const _Tp __cos2th = __x / __eta;
  76.       const _Tp __sin2th = _Tp(1) - __cos2th;
  77.       const _Tp __th = std::acos(std::sqrt(__cos2th));
  78.       const _Tp __pre_h = __numeric_constants<_Tp>::__pi_2()
  79.                         * __numeric_constants<_Tp>::__pi_2()
  80.                         * __eta * __eta * __cos2th * __sin2th;
  81.  
  82. #if _GLIBCXX_USE_C99_MATH_TR1
  83.       const _Tp __lg_b = std::tr1::lgamma(_Tp(__n) + __b);
  84.       const _Tp __lnfact = std::tr1::lgamma(_Tp(__n + 1));
  85. #else
  86.       const _Tp __lg_b = __log_gamma(_Tp(__n) + __b);
  87.       const _Tp __lnfact = __log_gamma(_Tp(__n + 1));
  88. #endif
  89.  
  90.       _Tp __pre_term1 = _Tp(0.5L) * (_Tp(1) - __b)
  91.                       * std::log(_Tp(0.25L) * __x * __eta);
  92.       _Tp __pre_term2 = _Tp(0.25L) * std::log(__pre_h);
  93.       _Tp __lnpre = __lg_b - __lnfact + _Tp(0.5L) * __x
  94.                       + __pre_term1 - __pre_term2;
  95.       _Tp __ser_term1 = std::sin(__a * __numeric_constants<_Tp>::__pi());
  96.       _Tp __ser_term2 = std::sin(_Tp(0.25L) * __eta
  97.                               * (_Tp(2) * __th
  98.                                - std::sin(_Tp(2) * __th))
  99.                                + __numeric_constants<_Tp>::__pi_4());
  100.       _Tp __ser = __ser_term1 + __ser_term2;
  101.  
  102.       return std::exp(__lnpre) * __ser;
  103.     }
  104.  
  105.  
  106.     /**
  107.      *  @brief  Evaluate the polynomial based on the confluent hypergeometric
  108.      *          function in a safe way, with no restriction on the arguments.
  109.      *
  110.      *   The associated Laguerre function is defined by
  111.      *   @f[
  112.      *       L_n^\alpha(x) = \frac{(\alpha + 1)_n}{n!}
  113.      *                       _1F_1(-n; \alpha + 1; x)
  114.      *   @f]
  115.      *   where @f$ (\alpha)_n @f$ is the Pochhammer symbol and
  116.      *   @f$ _1F_1(a; c; x) @f$ is the confluent hypergeometric function.
  117.      *
  118.      *  This function assumes x != 0.
  119.      *
  120.      *  This is from the GNU Scientific Library.
  121.      */
  122.     template<typename _Tpa, typename _Tp>
  123.     _Tp
  124.     __poly_laguerre_hyperg(unsigned int __n, _Tpa __alpha1, _Tp __x)
  125.     {
  126.       const _Tp __b = _Tp(__alpha1) + _Tp(1);
  127.       const _Tp __mx = -__x;
  128.       const _Tp __tc_sgn = (__x < _Tp(0) ? _Tp(1)
  129.                          : ((__n % 2 == 1) ? -_Tp(1) : _Tp(1)));
  130.       //  Get |x|^n/n!
  131.       _Tp __tc = _Tp(1);
  132.       const _Tp __ax = std::abs(__x);
  133.       for (unsigned int __k = 1; __k <= __n; ++__k)
  134.         __tc *= (__ax / __k);
  135.  
  136.       _Tp __term = __tc * __tc_sgn;
  137.       _Tp __sum = __term;
  138.       for (int __k = int(__n) - 1; __k >= 0; --__k)
  139.         {
  140.           __term *= ((__b + _Tp(__k)) / _Tp(int(__n) - __k))
  141.                   * _Tp(__k + 1) / __mx;
  142.           __sum += __term;
  143.         }
  144.  
  145.       return __sum;
  146.     }
  147.  
  148.  
  149.     /**
  150.      *   @brief This routine returns the associated Laguerre polynomial
  151.      *          of order @f$ n @f$, degree @f$ \alpha @f$: @f$ L_n^\alpha(x) @f$
  152.      *          by recursion.
  153.      *
  154.      *   The associated Laguerre function is defined by
  155.      *   @f[
  156.      *       L_n^\alpha(x) = \frac{(\alpha + 1)_n}{n!}
  157.      *                       _1F_1(-n; \alpha + 1; x)
  158.      *   @f]
  159.      *   where @f$ (\alpha)_n @f$ is the Pochhammer symbol and
  160.      *   @f$ _1F_1(a; c; x) @f$ is the confluent hypergeometric function.
  161.      *
  162.      *   The associated Laguerre polynomial is defined for integral
  163.      *   @f$ \alpha = m @f$ by:
  164.      *   @f[
  165.      *       L_n^m(x) = (-1)^m \frac{d^m}{dx^m} L_{n + m}(x)
  166.      *   @f]
  167.      *   where the Laguerre polynomial is defined by:
  168.      *   @f[
  169.      *       L_n(x) = \frac{e^x}{n!} \frac{d^n}{dx^n} (x^ne^{-x})
  170.      *   @f]
  171.      *
  172.      *   @param __n The order of the Laguerre function.
  173.      *   @param __alpha The degree of the Laguerre function.
  174.      *   @param __x The argument of the Laguerre function.
  175.      *   @return The value of the Laguerre function of order n,
  176.      *           degree @f$ \alpha @f$, and argument x.
  177.      */
  178.     template<typename _Tpa, typename _Tp>
  179.     _Tp
  180.     __poly_laguerre_recursion(unsigned int __n, _Tpa __alpha1, _Tp __x)
  181.     {
  182.       //   Compute l_0.
  183.       _Tp __l_0 = _Tp(1);
  184.       if  (__n == 0)
  185.         return __l_0;
  186.  
  187.       //  Compute l_1^alpha.
  188.       _Tp __l_1 = -__x + _Tp(1) + _Tp(__alpha1);
  189.       if  (__n == 1)
  190.         return __l_1;
  191.  
  192.       //  Compute l_n^alpha by recursion on n.
  193.       _Tp __l_n2 = __l_0;
  194.       _Tp __l_n1 = __l_1;
  195.       _Tp __l_n = _Tp(0);
  196.       for  (unsigned int __nn = 2; __nn <= __n; ++__nn)
  197.         {
  198.             __l_n = (_Tp(2 * __nn - 1) + _Tp(__alpha1) - __x)
  199.                   * __l_n1 / _Tp(__nn)
  200.                   - (_Tp(__nn - 1) + _Tp(__alpha1)) * __l_n2 / _Tp(__nn);
  201.             __l_n2 = __l_n1;
  202.             __l_n1 = __l_n;
  203.         }
  204.  
  205.       return __l_n;
  206.     }
  207.  
  208.  
  209.     /**
  210.      *   @brief This routine returns the associated Laguerre polynomial
  211.      *          of order n, degree @f$ \alpha @f$: @f$ L_n^alpha(x) @f$.
  212.      *
  213.      *   The associated Laguerre function is defined by
  214.      *   @f[
  215.      *       L_n^\alpha(x) = \frac{(\alpha + 1)_n}{n!}
  216.      *                       _1F_1(-n; \alpha + 1; x)
  217.      *   @f]
  218.      *   where @f$ (\alpha)_n @f$ is the Pochhammer symbol and
  219.      *   @f$ _1F_1(a; c; x) @f$ is the confluent hypergeometric function.
  220.      *
  221.      *   The associated Laguerre polynomial is defined for integral
  222.      *   @f$ \alpha = m @f$ by:
  223.      *   @f[
  224.      *       L_n^m(x) = (-1)^m \frac{d^m}{dx^m} L_{n + m}(x)
  225.      *   @f]
  226.      *   where the Laguerre polynomial is defined by:
  227.      *   @f[
  228.      *       L_n(x) = \frac{e^x}{n!} \frac{d^n}{dx^n} (x^ne^{-x})
  229.      *   @f]
  230.      *
  231.      *   @param __n The order of the Laguerre function.
  232.      *   @param __alpha The degree of the Laguerre function.
  233.      *   @param __x The argument of the Laguerre function.
  234.      *   @return The value of the Laguerre function of order n,
  235.      *           degree @f$ \alpha @f$, and argument x.
  236.      */
  237.     template<typename _Tpa, typename _Tp>
  238.     _Tp
  239.     __poly_laguerre(unsigned int __n, _Tpa __alpha1, _Tp __x)
  240.     {
  241.       if (__x < _Tp(0))
  242.         std::__throw_domain_error(__N("Negative argument "
  243.                                       "in __poly_laguerre."));
  244.       //  Return NaN on NaN input.
  245.       else if (__isnan(__x))
  246.         return std::numeric_limits<_Tp>::quiet_NaN();
  247.       else if (__n == 0)
  248.         return _Tp(1);
  249.       else if (__n == 1)
  250.         return _Tp(1) + _Tp(__alpha1) - __x;
  251.       else if (__x == _Tp(0))
  252.         {
  253.           _Tp __prod = _Tp(__alpha1) + _Tp(1);
  254.           for (unsigned int __k = 2; __k <= __n; ++__k)
  255.             __prod *= (_Tp(__alpha1) + _Tp(__k)) / _Tp(__k);
  256.           return __prod;
  257.         }
  258.       else if (__n > 10000000 && _Tp(__alpha1) > -_Tp(1)
  259.             && __x < _Tp(2) * (_Tp(__alpha1) + _Tp(1)) + _Tp(4 * __n))
  260.         return __poly_laguerre_large_n(__n, __alpha1, __x);
  261.       else if (_Tp(__alpha1) >= _Tp(0)
  262.            || (__x > _Tp(0) && _Tp(__alpha1) < -_Tp(__n + 1)))
  263.         return __poly_laguerre_recursion(__n, __alpha1, __x);
  264.       else
  265.         return __poly_laguerre_hyperg(__n, __alpha1, __x);
  266.     }
  267.  
  268.  
  269.     /**
  270.      *   @brief This routine returns the associated Laguerre polynomial
  271.      *          of order n, degree m: @f$ L_n^m(x) @f$.
  272.      *
  273.      *   The associated Laguerre polynomial is defined for integral
  274.      *   @f$ \alpha = m @f$ by:
  275.      *   @f[
  276.      *       L_n^m(x) = (-1)^m \frac{d^m}{dx^m} L_{n + m}(x)
  277.      *   @f]
  278.      *   where the Laguerre polynomial is defined by:
  279.      *   @f[
  280.      *       L_n(x) = \frac{e^x}{n!} \frac{d^n}{dx^n} (x^ne^{-x})
  281.      *   @f]
  282.      *
  283.      *   @param __n The order of the Laguerre polynomial.
  284.      *   @param __m The degree of the Laguerre polynomial.
  285.      *   @param __x The argument of the Laguerre polynomial.
  286.      *   @return The value of the associated Laguerre polynomial of order n,
  287.      *           degree m, and argument x.
  288.      */
  289.     template<typename _Tp>
  290.     inline _Tp
  291.     __assoc_laguerre(unsigned int __n, unsigned int __m, _Tp __x)
  292.     { return __poly_laguerre<unsigned int, _Tp>(__n, __m, __x); }
  293.  
  294.  
  295.     /**
  296.      *   @brief This routine returns the Laguerre polynomial
  297.      *          of order n: @f$ L_n(x) @f$.
  298.      *
  299.      *   The Laguerre polynomial is defined by:
  300.      *   @f[
  301.      *       L_n(x) = \frac{e^x}{n!} \frac{d^n}{dx^n} (x^ne^{-x})
  302.      *   @f]
  303.      *
  304.      *   @param __n The order of the Laguerre polynomial.
  305.      *   @param __x The argument of the Laguerre polynomial.
  306.      *   @return The value of the Laguerre polynomial of order n
  307.      *           and argument x.
  308.      */
  309.     template<typename _Tp>
  310.     inline _Tp
  311.     __laguerre(unsigned int __n, _Tp __x)
  312.     { return __poly_laguerre<unsigned int, _Tp>(__n, 0, __x); }
  313.  
  314.   _GLIBCXX_END_NAMESPACE_VERSION
  315.   } // namespace std::tr1::__detail
  316. }
  317. }
  318.  
  319. #endif // _GLIBCXX_TR1_POLY_LAGUERRE_TCC
  320.