xref: /dflybsd-src/contrib/gcc-4.7/libstdc++-v3/include/tr1/legendre_function.tcc (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino // Special functions -*- C++ -*-
2*e4b17023SJohn Marino 
3*e4b17023SJohn Marino // Copyright (C) 2006, 2007, 2008, 2009, 2010
4*e4b17023SJohn Marino // Free Software Foundation, Inc.
5*e4b17023SJohn Marino //
6*e4b17023SJohn Marino // This file is part of the GNU ISO C++ Library.  This library is free
7*e4b17023SJohn Marino // software; you can redistribute it and/or modify it under the
8*e4b17023SJohn Marino // terms of the GNU General Public License as published by the
9*e4b17023SJohn Marino // Free Software Foundation; either version 3, or (at your option)
10*e4b17023SJohn Marino // any later version.
11*e4b17023SJohn Marino //
12*e4b17023SJohn Marino // This library is distributed in the hope that it will be useful,
13*e4b17023SJohn Marino // but WITHOUT ANY WARRANTY; without even the implied warranty of
14*e4b17023SJohn Marino // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*e4b17023SJohn Marino // GNU General Public License for more details.
16*e4b17023SJohn Marino //
17*e4b17023SJohn Marino // Under Section 7 of GPL version 3, you are granted additional
18*e4b17023SJohn Marino // permissions described in the GCC Runtime Library Exception, version
19*e4b17023SJohn Marino // 3.1, as published by the Free Software Foundation.
20*e4b17023SJohn Marino 
21*e4b17023SJohn Marino // You should have received a copy of the GNU General Public License and
22*e4b17023SJohn Marino // a copy of the GCC Runtime Library Exception along with this program;
23*e4b17023SJohn Marino // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24*e4b17023SJohn Marino // <http://www.gnu.org/licenses/>.
25*e4b17023SJohn Marino 
26*e4b17023SJohn Marino /** @file tr1/legendre_function.tcc
27*e4b17023SJohn Marino  *  This is an internal header file, included by other library headers.
28*e4b17023SJohn Marino  *  Do not attempt to use it directly. @headername{tr1/cmath}
29*e4b17023SJohn Marino  */
30*e4b17023SJohn Marino 
31*e4b17023SJohn Marino //
32*e4b17023SJohn Marino // ISO C++ 14882 TR1: 5.2  Special functions
33*e4b17023SJohn Marino //
34*e4b17023SJohn Marino 
35*e4b17023SJohn Marino // Written by Edward Smith-Rowland based on:
36*e4b17023SJohn Marino //   (1) Handbook of Mathematical Functions,
37*e4b17023SJohn Marino //       ed. Milton Abramowitz and Irene A. Stegun,
38*e4b17023SJohn Marino //       Dover Publications,
39*e4b17023SJohn Marino //       Section 8, pp. 331-341
40*e4b17023SJohn Marino //   (2) The Gnu Scientific Library, http://www.gnu.org/software/gsl
41*e4b17023SJohn Marino //   (3) Numerical Recipes in C, by W. H. Press, S. A. Teukolsky,
42*e4b17023SJohn Marino //       W. T. Vetterling, B. P. Flannery, Cambridge University Press (1992),
43*e4b17023SJohn Marino //       2nd ed, pp. 252-254
44*e4b17023SJohn Marino 
45*e4b17023SJohn Marino #ifndef _GLIBCXX_TR1_LEGENDRE_FUNCTION_TCC
46*e4b17023SJohn Marino #define _GLIBCXX_TR1_LEGENDRE_FUNCTION_TCC 1
47*e4b17023SJohn Marino 
48*e4b17023SJohn Marino #include "special_function_util.h"
49*e4b17023SJohn Marino 
50*e4b17023SJohn Marino namespace std _GLIBCXX_VISIBILITY(default)
51*e4b17023SJohn Marino {
52*e4b17023SJohn Marino namespace tr1
53*e4b17023SJohn Marino {
54*e4b17023SJohn Marino   // [5.2] Special functions
55*e4b17023SJohn Marino 
56*e4b17023SJohn Marino   // Implementation-space details.
57*e4b17023SJohn Marino   namespace __detail
58*e4b17023SJohn Marino   {
59*e4b17023SJohn Marino   _GLIBCXX_BEGIN_NAMESPACE_VERSION
60*e4b17023SJohn Marino 
61*e4b17023SJohn Marino     /**
62*e4b17023SJohn Marino      *   @brief  Return the Legendre polynomial by recursion on order
63*e4b17023SJohn Marino      *           @f$ l @f$.
64*e4b17023SJohn Marino      *
65*e4b17023SJohn Marino      *   The Legendre function of @f$ l @f$ and @f$ x @f$,
66*e4b17023SJohn Marino      *   @f$ P_l(x) @f$, is defined by:
67*e4b17023SJohn Marino      *   @f[
68*e4b17023SJohn Marino      *     P_l(x) = \frac{1}{2^l l!}\frac{d^l}{dx^l}(x^2 - 1)^{l}
69*e4b17023SJohn Marino      *   @f]
70*e4b17023SJohn Marino      *
71*e4b17023SJohn Marino      *   @param  l  The order of the Legendre polynomial.  @f$l >= 0@f$.
72*e4b17023SJohn Marino      *   @param  x  The argument of the Legendre polynomial.  @f$|x| <= 1@f$.
73*e4b17023SJohn Marino      */
74*e4b17023SJohn Marino     template<typename _Tp>
75*e4b17023SJohn Marino     _Tp
__poly_legendre_p(const unsigned int __l,const _Tp __x)76*e4b17023SJohn Marino     __poly_legendre_p(const unsigned int __l, const _Tp __x)
77*e4b17023SJohn Marino     {
78*e4b17023SJohn Marino 
79*e4b17023SJohn Marino       if ((__x < _Tp(-1)) || (__x > _Tp(+1)))
80*e4b17023SJohn Marino         std::__throw_domain_error(__N("Argument out of range"
81*e4b17023SJohn Marino                                       " in __poly_legendre_p."));
82*e4b17023SJohn Marino       else if (__isnan(__x))
83*e4b17023SJohn Marino         return std::numeric_limits<_Tp>::quiet_NaN();
84*e4b17023SJohn Marino       else if (__x == +_Tp(1))
85*e4b17023SJohn Marino         return +_Tp(1);
86*e4b17023SJohn Marino       else if (__x == -_Tp(1))
87*e4b17023SJohn Marino         return (__l % 2 == 1 ? -_Tp(1) : +_Tp(1));
88*e4b17023SJohn Marino       else
89*e4b17023SJohn Marino         {
90*e4b17023SJohn Marino           _Tp __p_lm2 = _Tp(1);
91*e4b17023SJohn Marino           if (__l == 0)
92*e4b17023SJohn Marino             return __p_lm2;
93*e4b17023SJohn Marino 
94*e4b17023SJohn Marino           _Tp __p_lm1 = __x;
95*e4b17023SJohn Marino           if (__l == 1)
96*e4b17023SJohn Marino             return __p_lm1;
97*e4b17023SJohn Marino 
98*e4b17023SJohn Marino           _Tp __p_l = 0;
99*e4b17023SJohn Marino           for (unsigned int __ll = 2; __ll <= __l; ++__ll)
100*e4b17023SJohn Marino             {
101*e4b17023SJohn Marino               //  This arrangement is supposed to be better for roundoff
102*e4b17023SJohn Marino               //  protection, Arfken, 2nd Ed, Eq 12.17a.
103*e4b17023SJohn Marino               __p_l = _Tp(2) * __x * __p_lm1 - __p_lm2
104*e4b17023SJohn Marino                     - (__x * __p_lm1 - __p_lm2) / _Tp(__ll);
105*e4b17023SJohn Marino               __p_lm2 = __p_lm1;
106*e4b17023SJohn Marino               __p_lm1 = __p_l;
107*e4b17023SJohn Marino             }
108*e4b17023SJohn Marino 
109*e4b17023SJohn Marino           return __p_l;
110*e4b17023SJohn Marino         }
111*e4b17023SJohn Marino     }
112*e4b17023SJohn Marino 
113*e4b17023SJohn Marino 
114*e4b17023SJohn Marino     /**
115*e4b17023SJohn Marino      *   @brief  Return the associated Legendre function by recursion
116*e4b17023SJohn Marino      *           on @f$ l @f$.
117*e4b17023SJohn Marino      *
118*e4b17023SJohn Marino      *   The associated Legendre function is derived from the Legendre function
119*e4b17023SJohn Marino      *   @f$ P_l(x) @f$ by the Rodrigues formula:
120*e4b17023SJohn Marino      *   @f[
121*e4b17023SJohn Marino      *     P_l^m(x) = (1 - x^2)^{m/2}\frac{d^m}{dx^m}P_l(x)
122*e4b17023SJohn Marino      *   @f]
123*e4b17023SJohn Marino      *
124*e4b17023SJohn Marino      *   @param  l  The order of the associated Legendre function.
125*e4b17023SJohn Marino      *              @f$ l >= 0 @f$.
126*e4b17023SJohn Marino      *   @param  m  The order of the associated Legendre function.
127*e4b17023SJohn Marino      *              @f$ m <= l @f$.
128*e4b17023SJohn Marino      *   @param  x  The argument of the associated Legendre function.
129*e4b17023SJohn Marino      *              @f$ |x| <= 1 @f$.
130*e4b17023SJohn Marino      */
131*e4b17023SJohn Marino     template<typename _Tp>
132*e4b17023SJohn Marino     _Tp
__assoc_legendre_p(const unsigned int __l,const unsigned int __m,const _Tp __x)133*e4b17023SJohn Marino     __assoc_legendre_p(const unsigned int __l, const unsigned int __m,
134*e4b17023SJohn Marino                        const _Tp __x)
135*e4b17023SJohn Marino     {
136*e4b17023SJohn Marino 
137*e4b17023SJohn Marino       if (__x < _Tp(-1) || __x > _Tp(+1))
138*e4b17023SJohn Marino         std::__throw_domain_error(__N("Argument out of range"
139*e4b17023SJohn Marino                                       " in __assoc_legendre_p."));
140*e4b17023SJohn Marino       else if (__m > __l)
141*e4b17023SJohn Marino         std::__throw_domain_error(__N("Degree out of range"
142*e4b17023SJohn Marino                                       " in __assoc_legendre_p."));
143*e4b17023SJohn Marino       else if (__isnan(__x))
144*e4b17023SJohn Marino         return std::numeric_limits<_Tp>::quiet_NaN();
145*e4b17023SJohn Marino       else if (__m == 0)
146*e4b17023SJohn Marino         return __poly_legendre_p(__l, __x);
147*e4b17023SJohn Marino       else
148*e4b17023SJohn Marino         {
149*e4b17023SJohn Marino           _Tp __p_mm = _Tp(1);
150*e4b17023SJohn Marino           if (__m > 0)
151*e4b17023SJohn Marino             {
152*e4b17023SJohn Marino               //  Two square roots seem more accurate more of the time
153*e4b17023SJohn Marino               //  than just one.
154*e4b17023SJohn Marino               _Tp __root = std::sqrt(_Tp(1) - __x) * std::sqrt(_Tp(1) + __x);
155*e4b17023SJohn Marino               _Tp __fact = _Tp(1);
156*e4b17023SJohn Marino               for (unsigned int __i = 1; __i <= __m; ++__i)
157*e4b17023SJohn Marino                 {
158*e4b17023SJohn Marino                   __p_mm *= -__fact * __root;
159*e4b17023SJohn Marino                   __fact += _Tp(2);
160*e4b17023SJohn Marino                 }
161*e4b17023SJohn Marino             }
162*e4b17023SJohn Marino           if (__l == __m)
163*e4b17023SJohn Marino             return __p_mm;
164*e4b17023SJohn Marino 
165*e4b17023SJohn Marino           _Tp __p_mp1m = _Tp(2 * __m + 1) * __x * __p_mm;
166*e4b17023SJohn Marino           if (__l == __m + 1)
167*e4b17023SJohn Marino             return __p_mp1m;
168*e4b17023SJohn Marino 
169*e4b17023SJohn Marino           _Tp __p_lm2m = __p_mm;
170*e4b17023SJohn Marino           _Tp __P_lm1m = __p_mp1m;
171*e4b17023SJohn Marino           _Tp __p_lm = _Tp(0);
172*e4b17023SJohn Marino           for (unsigned int __j = __m + 2; __j <= __l; ++__j)
173*e4b17023SJohn Marino             {
174*e4b17023SJohn Marino               __p_lm = (_Tp(2 * __j - 1) * __x * __P_lm1m
175*e4b17023SJohn Marino                       - _Tp(__j + __m - 1) * __p_lm2m) / _Tp(__j - __m);
176*e4b17023SJohn Marino               __p_lm2m = __P_lm1m;
177*e4b17023SJohn Marino               __P_lm1m = __p_lm;
178*e4b17023SJohn Marino             }
179*e4b17023SJohn Marino 
180*e4b17023SJohn Marino           return __p_lm;
181*e4b17023SJohn Marino         }
182*e4b17023SJohn Marino     }
183*e4b17023SJohn Marino 
184*e4b17023SJohn Marino 
185*e4b17023SJohn Marino     /**
186*e4b17023SJohn Marino      *   @brief  Return the spherical associated Legendre function.
187*e4b17023SJohn Marino      *
188*e4b17023SJohn Marino      *   The spherical associated Legendre function of @f$ l @f$, @f$ m @f$,
189*e4b17023SJohn Marino      *   and @f$ \theta @f$ is defined as @f$ Y_l^m(\theta,0) @f$ where
190*e4b17023SJohn Marino      *   @f[
191*e4b17023SJohn Marino      *      Y_l^m(\theta,\phi) = (-1)^m[\frac{(2l+1)}{4\pi}
192*e4b17023SJohn Marino      *                                  \frac{(l-m)!}{(l+m)!}]
193*e4b17023SJohn Marino      *                     P_l^m(\cos\theta) \exp^{im\phi}
194*e4b17023SJohn Marino      *   @f]
195*e4b17023SJohn Marino      *   is the spherical harmonic function and @f$ P_l^m(x) @f$ is the
196*e4b17023SJohn Marino      *   associated Legendre function.
197*e4b17023SJohn Marino      *
198*e4b17023SJohn Marino      *   This function differs from the associated Legendre function by
199*e4b17023SJohn Marino      *   argument (@f$x = \cos(\theta)@f$) and by a normalization factor
200*e4b17023SJohn Marino      *   but this factor is rather large for large @f$ l @f$ and @f$ m @f$
201*e4b17023SJohn Marino      *   and so this function is stable for larger differences of @f$ l @f$
202*e4b17023SJohn Marino      *   and @f$ m @f$.
203*e4b17023SJohn Marino      *
204*e4b17023SJohn Marino      *   @param  l  The order of the spherical associated Legendre function.
205*e4b17023SJohn Marino      *              @f$ l >= 0 @f$.
206*e4b17023SJohn Marino      *   @param  m  The order of the spherical associated Legendre function.
207*e4b17023SJohn Marino      *              @f$ m <= l @f$.
208*e4b17023SJohn Marino      *   @param  theta  The radian angle argument of the spherical associated
209*e4b17023SJohn Marino      *                  Legendre function.
210*e4b17023SJohn Marino      */
211*e4b17023SJohn Marino     template <typename _Tp>
212*e4b17023SJohn Marino     _Tp
__sph_legendre(const unsigned int __l,const unsigned int __m,const _Tp __theta)213*e4b17023SJohn Marino     __sph_legendre(const unsigned int __l, const unsigned int __m,
214*e4b17023SJohn Marino                    const _Tp __theta)
215*e4b17023SJohn Marino     {
216*e4b17023SJohn Marino       if (__isnan(__theta))
217*e4b17023SJohn Marino         return std::numeric_limits<_Tp>::quiet_NaN();
218*e4b17023SJohn Marino 
219*e4b17023SJohn Marino       const _Tp __x = std::cos(__theta);
220*e4b17023SJohn Marino 
221*e4b17023SJohn Marino       if (__l < __m)
222*e4b17023SJohn Marino         {
223*e4b17023SJohn Marino           std::__throw_domain_error(__N("Bad argument "
224*e4b17023SJohn Marino                                         "in __sph_legendre."));
225*e4b17023SJohn Marino         }
226*e4b17023SJohn Marino       else if (__m == 0)
227*e4b17023SJohn Marino         {
228*e4b17023SJohn Marino           _Tp __P = __poly_legendre_p(__l, __x);
229*e4b17023SJohn Marino           _Tp __fact = std::sqrt(_Tp(2 * __l + 1)
230*e4b17023SJohn Marino                      / (_Tp(4) * __numeric_constants<_Tp>::__pi()));
231*e4b17023SJohn Marino           __P *= __fact;
232*e4b17023SJohn Marino           return __P;
233*e4b17023SJohn Marino         }
234*e4b17023SJohn Marino       else if (__x == _Tp(1) || __x == -_Tp(1))
235*e4b17023SJohn Marino         {
236*e4b17023SJohn Marino           //  m > 0 here
237*e4b17023SJohn Marino           return _Tp(0);
238*e4b17023SJohn Marino         }
239*e4b17023SJohn Marino       else
240*e4b17023SJohn Marino         {
241*e4b17023SJohn Marino           // m > 0 and |x| < 1 here
242*e4b17023SJohn Marino 
243*e4b17023SJohn Marino           // Starting value for recursion.
244*e4b17023SJohn Marino           // Y_m^m(x) = sqrt( (2m+1)/(4pi m) gamma(m+1/2)/gamma(m) )
245*e4b17023SJohn Marino           //             (-1)^m (1-x^2)^(m/2) / pi^(1/4)
246*e4b17023SJohn Marino           const _Tp __sgn = ( __m % 2 == 1 ? -_Tp(1) : _Tp(1));
247*e4b17023SJohn Marino           const _Tp __y_mp1m_factor = __x * std::sqrt(_Tp(2 * __m + 3));
248*e4b17023SJohn Marino #if _GLIBCXX_USE_C99_MATH_TR1
249*e4b17023SJohn Marino           const _Tp __lncirc = std::tr1::log1p(-__x * __x);
250*e4b17023SJohn Marino #else
251*e4b17023SJohn Marino           const _Tp __lncirc = std::log(_Tp(1) - __x * __x);
252*e4b17023SJohn Marino #endif
253*e4b17023SJohn Marino           //  Gamma(m+1/2) / Gamma(m)
254*e4b17023SJohn Marino #if _GLIBCXX_USE_C99_MATH_TR1
255*e4b17023SJohn Marino           const _Tp __lnpoch = std::tr1::lgamma(_Tp(__m + _Tp(0.5L)))
256*e4b17023SJohn Marino                              - std::tr1::lgamma(_Tp(__m));
257*e4b17023SJohn Marino #else
258*e4b17023SJohn Marino           const _Tp __lnpoch = __log_gamma(_Tp(__m + _Tp(0.5L)))
259*e4b17023SJohn Marino                              - __log_gamma(_Tp(__m));
260*e4b17023SJohn Marino #endif
261*e4b17023SJohn Marino           const _Tp __lnpre_val =
262*e4b17023SJohn Marino                     -_Tp(0.25L) * __numeric_constants<_Tp>::__lnpi()
263*e4b17023SJohn Marino                     + _Tp(0.5L) * (__lnpoch + __m * __lncirc);
264*e4b17023SJohn Marino           _Tp __sr = std::sqrt((_Tp(2) + _Tp(1) / __m)
265*e4b17023SJohn Marino                    / (_Tp(4) * __numeric_constants<_Tp>::__pi()));
266*e4b17023SJohn Marino           _Tp __y_mm = __sgn * __sr * std::exp(__lnpre_val);
267*e4b17023SJohn Marino           _Tp __y_mp1m = __y_mp1m_factor * __y_mm;
268*e4b17023SJohn Marino 
269*e4b17023SJohn Marino           if (__l == __m)
270*e4b17023SJohn Marino             {
271*e4b17023SJohn Marino               return __y_mm;
272*e4b17023SJohn Marino             }
273*e4b17023SJohn Marino           else if (__l == __m + 1)
274*e4b17023SJohn Marino             {
275*e4b17023SJohn Marino               return __y_mp1m;
276*e4b17023SJohn Marino             }
277*e4b17023SJohn Marino           else
278*e4b17023SJohn Marino             {
279*e4b17023SJohn Marino               _Tp __y_lm = _Tp(0);
280*e4b17023SJohn Marino 
281*e4b17023SJohn Marino               // Compute Y_l^m, l > m+1, upward recursion on l.
282*e4b17023SJohn Marino               for ( int __ll = __m + 2; __ll <= __l; ++__ll)
283*e4b17023SJohn Marino                 {
284*e4b17023SJohn Marino                   const _Tp __rat1 = _Tp(__ll - __m) / _Tp(__ll + __m);
285*e4b17023SJohn Marino                   const _Tp __rat2 = _Tp(__ll - __m - 1) / _Tp(__ll + __m - 1);
286*e4b17023SJohn Marino                   const _Tp __fact1 = std::sqrt(__rat1 * _Tp(2 * __ll + 1)
287*e4b17023SJohn Marino                                                        * _Tp(2 * __ll - 1));
288*e4b17023SJohn Marino                   const _Tp __fact2 = std::sqrt(__rat1 * __rat2 * _Tp(2 * __ll + 1)
289*e4b17023SJohn Marino                                                                 / _Tp(2 * __ll - 3));
290*e4b17023SJohn Marino                   __y_lm = (__x * __y_mp1m * __fact1
291*e4b17023SJohn Marino                          - (__ll + __m - 1) * __y_mm * __fact2) / _Tp(__ll - __m);
292*e4b17023SJohn Marino                   __y_mm = __y_mp1m;
293*e4b17023SJohn Marino                   __y_mp1m = __y_lm;
294*e4b17023SJohn Marino                 }
295*e4b17023SJohn Marino 
296*e4b17023SJohn Marino               return __y_lm;
297*e4b17023SJohn Marino             }
298*e4b17023SJohn Marino         }
299*e4b17023SJohn Marino     }
300*e4b17023SJohn Marino 
301*e4b17023SJohn Marino   _GLIBCXX_END_NAMESPACE_VERSION
302*e4b17023SJohn Marino   } // namespace std::tr1::__detail
303*e4b17023SJohn Marino }
304*e4b17023SJohn Marino }
305*e4b17023SJohn Marino 
306*e4b17023SJohn Marino #endif // _GLIBCXX_TR1_LEGENDRE_FUNCTION_TCC
307