expn.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* expn.c
  2. *
  3. * Exponential integral En
  4. *
  5. *
  6. *
  7. * SYNOPSIS:
  8. *
  9. * int n;
  10. * double x, y, expn();
  11. *
  12. * y = expn( n, x );
  13. *
  14. *
  15. *
  16. * DESCRIPTION:
  17. *
  18. * Evaluates the exponential integral
  19. *
  20. * inf.
  21. * -
  22. * | | -xt
  23. * | e
  24. * E (x) = | ---- dt.
  25. * n | n
  26. * | | t
  27. * -
  28. * 1
  29. *
  30. *
  31. * Both n and x must be nonnegative.
  32. *
  33. * The routine employs either a power series, a continued
  34. * fraction, or an asymptotic formula depending on the
  35. * relative values of n and x.
  36. *
  37. * ACCURACY:
  38. *
  39. * Relative error:
  40. * arithmetic domain # trials peak rms
  41. * DEC 0, 30 5000 2.0e-16 4.6e-17
  42. * IEEE 0, 30 10000 1.7e-15 3.6e-16
  43. *
  44. */
  45. /* expn.c */
  46. /* Cephes Math Library Release 2.8: June, 2000
  47. Copyright 1985, 2000 by Stephen L. Moshier */
  48. #include <math.h>
  49. #ifdef ANSIPROT
  50. extern double pow ( double, double );
  51. extern double gamma ( double );
  52. extern double log ( double );
  53. extern double exp ( double );
  54. extern double fabs ( double );
  55. #else
  56. double pow(), gamma(), log(), exp(), fabs();
  57. #endif
  58. #define EUL 0.57721566490153286060
  59. #define BIG 1.44115188075855872E+17
  60. extern double MAXNUM, MACHEP, MAXLOG;
  61. double expn( n, x )
  62. int n;
  63. double x;
  64. {
  65. double ans, r, t, yk, xk;
  66. double pk, pkm1, pkm2, qk, qkm1, qkm2;
  67. double psi, z;
  68. int i, k;
  69. static double big = BIG;
  70. if( n < 0 )
  71. goto domerr;
  72. if( x < 0 )
  73. {
  74. domerr: mtherr( "expn", DOMAIN );
  75. return( MAXNUM );
  76. }
  77. if( x > MAXLOG )
  78. return( 0.0 );
  79. if( x == 0.0 )
  80. {
  81. if( n < 2 )
  82. {
  83. mtherr( "expn", SING );
  84. return( MAXNUM );
  85. }
  86. else
  87. return( 1.0/(n-1.0) );
  88. }
  89. if( n == 0 )
  90. return( exp(-x)/x );
  91. /* expn.c */
  92. /* Expansion for large n */
  93. if( n > 5000 )
  94. {
  95. xk = x + n;
  96. yk = 1.0 / (xk * xk);
  97. t = n;
  98. ans = yk * t * (6.0 * x * x - 8.0 * t * x + t * t);
  99. ans = yk * (ans + t * (t - 2.0 * x));
  100. ans = yk * (ans + t);
  101. ans = (ans + 1.0) * exp( -x ) / xk;
  102. goto done;
  103. }
  104. if( x > 1.0 )
  105. goto cfrac;
  106. /* expn.c */
  107. /* Power series expansion */
  108. psi = -EUL - log(x);
  109. for( i=1; i<n; i++ )
  110. psi = psi + 1.0/i;
  111. z = -x;
  112. xk = 0.0;
  113. yk = 1.0;
  114. pk = 1.0 - n;
  115. if( n == 1 )
  116. ans = 0.0;
  117. else
  118. ans = 1.0/pk;
  119. do
  120. {
  121. xk += 1.0;
  122. yk *= z/xk;
  123. pk += 1.0;
  124. if( pk != 0.0 )
  125. {
  126. ans += yk/pk;
  127. }
  128. if( ans != 0.0 )
  129. t = fabs(yk/ans);
  130. else
  131. t = 1.0;
  132. }
  133. while( t > MACHEP );
  134. k = xk;
  135. t = n;
  136. r = n - 1;
  137. ans = (pow(z, r) * psi / gamma(t)) - ans;
  138. goto done;
  139. /* expn.c */
  140. /* continued fraction */
  141. cfrac:
  142. k = 1;
  143. pkm2 = 1.0;
  144. qkm2 = x;
  145. pkm1 = 1.0;
  146. qkm1 = x + n;
  147. ans = pkm1/qkm1;
  148. do
  149. {
  150. k += 1;
  151. if( k & 1 )
  152. {
  153. yk = 1.0;
  154. xk = n + (k-1)/2;
  155. }
  156. else
  157. {
  158. yk = x;
  159. xk = k/2;
  160. }
  161. pk = pkm1 * yk + pkm2 * xk;
  162. qk = qkm1 * yk + qkm2 * xk;
  163. if( qk != 0 )
  164. {
  165. r = pk/qk;
  166. t = fabs( (ans - r)/r );
  167. ans = r;
  168. }
  169. else
  170. t = 1.0;
  171. pkm2 = pkm1;
  172. pkm1 = pk;
  173. qkm2 = qkm1;
  174. qkm1 = qk;
  175. if( fabs(pk) > big )
  176. {
  177. pkm2 /= big;
  178. pkm1 /= big;
  179. qkm2 /= big;
  180. qkm1 /= big;
  181. }
  182. }
  183. while( t > MACHEP );
  184. ans *= exp( -x );
  185. done:
  186. return( ans );
  187. }