POK
/home/jaouen/pok_official/pok/trunk/libpok/libm/e_jn.c
00001 /*
00002  *                               POK header
00003  * 
00004  * The following file is a part of the POK project. Any modification should
00005  * made according to the POK licence. You CANNOT use this file or a part of
00006  * this file is this part of a file for your own project
00007  *
00008  * For more information on the POK licence, please see our LICENCE FILE
00009  *
00010  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
00011  *
00012  *                                      Copyright (c) 2007-2009 POK team 
00013  *
00014  * Created by julien on Fri Jan 30 14:41:34 2009 
00015  */
00016 
00017 /* @(#)e_jn.c 5.1 93/09/24 */
00018 /*
00019  * ====================================================
00020  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00021  *
00022  * Developed at SunPro, a Sun Microsystems, Inc. business.
00023  * Permission to use, copy, modify, and distribute this
00024  * software is freely granted, provided that this notice
00025  * is preserved.
00026  * ====================================================
00027  */
00028 
00029 /*
00030  * __ieee754_jn(n, x), __ieee754_yn(n, x)
00031  * floating point Bessel's function of the 1st and 2nd kind
00032  * of order n
00033  *
00034  * Special cases:
00035  *      y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
00036  *      y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
00037  * Note 2. About jn(n,x), yn(n,x)
00038  *      For n=0, j0(x) is called,
00039  *      for n=1, j1(x) is called,
00040  *      for n<x, forward recursion us used starting
00041  *      from values of j0(x) and j1(x).
00042  *      for n>x, a continued fraction approximation to
00043  *      j(n,x)/j(n-1,x) is evaluated and then backward
00044  *      recursion is used starting from a supposed value
00045  *      for j(n,x). The resulting value of j(0,x) is
00046  *      compared with the actual value to correct the
00047  *      supposed value of j(n,x).
00048  *
00049  *      yn(n,x) is similar in all respects, except
00050  *      that forward recursion is used for all
00051  *      values of n>1.
00052  *
00053  */
00054 
00055 #ifdef POK_NEEDS_LIBMATH
00056 
00057 #include "namespace.h"
00058 #include "math_private.h"
00059 #include <libm.h>
00060 
00061 static const double
00062 invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
00063 two   =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
00064 one   =  1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
00065 
00066 static const double zero  =  0.00000000000000000000e+00;
00067 
00068 double
00069 __ieee754_jn(int n, double x)
00070 {
00071         int32_t i,hx,ix,lx, sgn;
00072         double a, b, temp, di;
00073         double z, w;
00074 
00075         temp = 0;
00076     /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
00077      * Thus, J(-n,x) = J(n,-x)
00078      */
00079         EXTRACT_WORDS(hx,lx,x);
00080         ix = 0x7fffffff&hx;
00081     /* if J(n,NaN) is NaN */
00082         if((ix|((uint32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
00083         if(n<0){
00084                 n = -n;
00085                 x = -x;
00086                 hx ^= 0x80000000;
00087         }
00088         if(n==0) return(__ieee754_j0(x));
00089         if(n==1) return(__ieee754_j1(x));
00090         sgn = (n&1)&(hx>>31);   /* even n -- 0, odd n -- sign(x) */
00091         x = fabs(x);
00092         if((ix|lx)==0||ix>=0x7ff00000)  /* if x is 0 or inf */
00093             b = zero;
00094         else if((double)n<=x) {
00095                 /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
00096             if(ix>=0x52D00000) { /* x > 2**302 */
00097     /* (x >> n**2)
00098      *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
00099      *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
00100      *      Let s=sin(x), c=cos(x),
00101      *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
00102      *
00103      *             n    sin(xn)*sqt2    cos(xn)*sqt2
00104      *          ----------------------------------
00105      *             0     s-c             c+s
00106      *             1    -s-c            -c+s
00107      *             2    -s+c            -c-s
00108      *             3     s+c             c-s
00109      */
00110                 switch(n&3) {
00111                     case 0: temp =  cos(x)+sin(x); break;
00112                     case 1: temp = -cos(x)+sin(x); break;
00113                     case 2: temp = -cos(x)-sin(x); break;
00114                     case 3: temp =  cos(x)-sin(x); break;
00115                 }
00116                 b = invsqrtpi*temp/sqrt(x);
00117             } else {
00118                 a = __ieee754_j0(x);
00119                 b = __ieee754_j1(x);
00120                 for(i=1;i<n;i++){
00121                     temp = b;
00122                     b = b*((double)(i+i)/x) - a; /* avoid underflow */
00123                     a = temp;
00124                 }
00125             }
00126         } else {
00127             if(ix<0x3e100000) { /* x < 2**-29 */
00128     /* x is tiny, return the first Taylor expansion of J(n,x)
00129      * J(n,x) = 1/n!*(x/2)^n  - ...
00130      */
00131                 if(n>33)        /* underflow */
00132                     b = zero;
00133                 else {
00134                     temp = x*0.5; b = temp;
00135                     for (a=one,i=2;i<=n;i++) {
00136                         a *= (double)i;         /* a = n! */
00137                         b *= temp;              /* b = (x/2)^n */
00138                     }
00139                     b = b/a;
00140                 }
00141             } else {
00142                 /* use backward recurrence */
00143                 /*                      x      x^2      x^2
00144                  *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
00145                  *                      2n  - 2(n+1) - 2(n+2)
00146                  *
00147                  *                      1      1        1
00148                  *  (for large x)   =  ----  ------   ------   .....
00149                  *                      2n   2(n+1)   2(n+2)
00150                  *                      -- - ------ - ------ -
00151                  *                       x     x         x
00152                  *
00153                  * Let w = 2n/x and h=2/x, then the above quotient
00154                  * is equal to the continued fraction:
00155                  *                  1
00156                  *      = -----------------------
00157                  *                     1
00158                  *         w - -----------------
00159                  *                        1
00160                  *              w+h - ---------
00161                  *                     w+2h - ...
00162                  *
00163                  * To determine how many terms needed, let
00164                  * Q(0) = w, Q(1) = w(w+h) - 1,
00165                  * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
00166                  * When Q(k) > 1e4      good for single
00167                  * When Q(k) > 1e9      good for double
00168                  * When Q(k) > 1e17     good for quadruple
00169                  */
00170             /* determine k */
00171                 double t,v;
00172                 double q0,q1,h,tmp; int32_t k,m;
00173                 w  = (n+n)/(double)x; h = 2.0/(double)x;
00174                 q0 = w;  z = w+h; q1 = w*z - 1.0; k=1;
00175                 while(q1<1.0e9) {
00176                         k += 1; z += h;
00177                         tmp = z*q1 - q0;
00178                         q0 = q1;
00179                         q1 = tmp;
00180                 }
00181                 m = n+n;
00182                 for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
00183                 a = t;
00184                 b = one;
00185                 /*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
00186                  *  Hence, if n*(log(2n/x)) > ...
00187                  *  single 8.8722839355e+01
00188                  *  double 7.09782712893383973096e+02
00189                  *  long double 1.1356523406294143949491931077970765006170e+04
00190                  *  then recurrent value may overflow and the result is
00191                  *  likely underflow to zero
00192                  */
00193                 tmp = n;
00194                 v = two/x;
00195                 tmp = tmp*__ieee754_log(fabs(v*tmp));
00196                 if(tmp<7.09782712893383973096e+02) {
00197                     for(i=n-1,di=(double)(i+i);i>0;i--){
00198                         temp = b;
00199                         b *= di;
00200                         b  = b/x - a;
00201                         a = temp;
00202                         di -= two;
00203                     }
00204                 } else {
00205                     for(i=n-1,di=(double)(i+i);i>0;i--){
00206                         temp = b;
00207                         b *= di;
00208                         b  = b/x - a;
00209                         a = temp;
00210                         di -= two;
00211                     /* scale b to avoid spurious overflow */
00212                         if(b>1e100) {
00213                             a /= b;
00214                             t /= b;
00215                             b  = one;
00216                         }
00217                     }
00218                 }
00219                 b = (t*__ieee754_j0(x)/b);
00220             }
00221         }
00222         if(sgn==1) return -b; else return b;
00223 }
00224 
00225 double
00226 __ieee754_yn(int n, double x)
00227 {
00228         int32_t i,hx,ix,lx;
00229         int32_t sign;
00230         double a, b, temp;
00231 
00232         temp = 0;
00233         EXTRACT_WORDS(hx,lx,x);
00234         ix = 0x7fffffff&hx;
00235     /* if Y(n,NaN) is NaN */
00236         if((ix|((uint32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
00237         if((ix|lx)==0) return -one/zero;
00238         if(hx<0) return zero/zero;
00239         sign = 1;
00240         if(n<0){
00241                 n = -n;
00242                 sign = 1 - ((n&1)<<1);
00243         }
00244         if(n==0) return(__ieee754_y0(x));
00245         if(n==1) return(sign*__ieee754_y1(x));
00246         if(ix==0x7ff00000) return zero;
00247         if(ix>=0x52D00000) { /* x > 2**302 */
00248     /* (x >> n**2)
00249      *      Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
00250      *      Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
00251      *      Let s=sin(x), c=cos(x),
00252      *          xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
00253      *
00254      *             n    sin(xn)*sqt2    cos(xn)*sqt2
00255      *          ----------------------------------
00256      *             0     s-c             c+s
00257      *             1    -s-c            -c+s
00258      *             2    -s+c            -c-s
00259      *             3     s+c             c-s
00260      */
00261                 switch(n&3) {
00262                     case 0: temp =  sin(x)-cos(x); break;
00263                     case 1: temp = -sin(x)-cos(x); break;
00264                     case 2: temp = -sin(x)+cos(x); break;
00265                     case 3: temp =  sin(x)+cos(x); break;
00266                 }
00267                 b = invsqrtpi*temp/sqrt(x);
00268         } else {
00269             uint32_t high;
00270             a = __ieee754_y0(x);
00271             b = __ieee754_y1(x);
00272         /* quit if b is -inf */
00273             GET_HIGH_WORD(high,b);
00274             for(i=1;i<n&&high!=0xfff00000;i++){
00275                 temp = b;
00276                 b = ((double)(i+i)/x)*b - a;
00277                 GET_HIGH_WORD(high,b);
00278                 a = temp;
00279             }
00280         }
00281         if(sign>0) return b; else return -b;
00282 }
00283 #endif
00284