expn.c
Go to the documentation of this file.
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  * IEEE 0, 30 10000 1.7e-15 3.6e-16
42  *
43  */
44 
45 /* expn.c */
46 
47 /* Cephes Math Library Release 1.1: March, 1985
48  * Copyright 1985 by Stephen L. Moshier
49  * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */
50 
51 /* Sources
52  * [1] NIST, "The Digital Library of Mathematical Functions", dlmf.nist.gov
53  */
54 
55 /* Scipy changes:
56  * - 09-10-2016: improved asymptotic expansion for large n
57  */
58 
59 #include "mconf.h"
60 #include "polevl.h"
61 #include "expn.h"
62 
63 #define EUL 0.57721566490153286060
64 #define BIG 1.44115188075855872E+17
65 extern double MACHEP, MAXLOG;
66 
67 static double expn_large_n(int, double);
68 
69 
70 double expn(int n, double x)
71 {
72  double ans, r, t, yk, xk;
73  double pk, pkm1, pkm2, qk, qkm1, qkm2;
74  double psi, z;
75  int i, k;
76  static double big = BIG;
77 
78  if (isnan(x)) {
79  return NAN;
80  }
81  else if (n < 0 || x < 0) {
82  sf_error("expn", SF_ERROR_DOMAIN, NULL);
83  return NAN;
84  }
85 
86  if (x > MAXLOG) {
87  return (0.0);
88  }
89 
90  if (x == 0.0) {
91  if (n < 2) {
93  return (INFINITY);
94  }
95  else {
96  return (1.0 / (n - 1.0));
97  }
98  }
99 
100  if (n == 0) {
101  return (exp(-x) / x);
102  }
103 
104  /* Asymptotic expansion for large n, DLMF 8.20(ii) */
105  if (n > 50) {
106  ans = expn_large_n(n, x);
107  goto done;
108  }
109 
110  if (x > 1.0) {
111  goto cfrac;
112  }
113 
114  /* Power series expansion, DLMF 8.19.8 */
115  psi = -EUL - log(x);
116  for (i = 1; i < n; i++) {
117  psi = psi + 1.0 / i;
118  }
119 
120  z = -x;
121  xk = 0.0;
122  yk = 1.0;
123  pk = 1.0 - n;
124  if (n == 1) {
125  ans = 0.0;
126  } else {
127  ans = 1.0 / pk;
128  }
129  do {
130  xk += 1.0;
131  yk *= z / xk;
132  pk += 1.0;
133  if (pk != 0.0) {
134  ans += yk / pk;
135  }
136  if (ans != 0.0)
137  t = fabs(yk / ans);
138  else
139  t = 1.0;
140  } while (t > MACHEP);
141  k = xk;
142  t = n;
143  r = n - 1;
144  ans = (pow(z, r) * psi / Gamma(t)) - ans;
145  goto done;
146 
147  /* Continued fraction, DLMF 8.19.17 */
148  cfrac:
149  k = 1;
150  pkm2 = 1.0;
151  qkm2 = x;
152  pkm1 = 1.0;
153  qkm1 = x + n;
154  ans = pkm1 / qkm1;
155 
156  do {
157  k += 1;
158  if (k & 1) {
159  yk = 1.0;
160  xk = n + (k - 1) / 2;
161  } else {
162  yk = x;
163  xk = k / 2;
164  }
165  pk = pkm1 * yk + pkm2 * xk;
166  qk = qkm1 * yk + qkm2 * xk;
167  if (qk != 0) {
168  r = pk / qk;
169  t = fabs((ans - r) / r);
170  ans = r;
171  } else {
172  t = 1.0;
173  }
174  pkm2 = pkm1;
175  pkm1 = pk;
176  qkm2 = qkm1;
177  qkm1 = qk;
178  if (fabs(pk) > big) {
179  pkm2 /= big;
180  pkm1 /= big;
181  qkm2 /= big;
182  qkm1 /= big;
183  }
184  } while (t > MACHEP);
185 
186  ans *= exp(-x);
187 
188  done:
189  return (ans);
190 }
191 
192 
193 /* Asymptotic expansion for large n, DLMF 8.20(ii) */
194 static double expn_large_n(int n, double x)
195 {
196  int k;
197  double p = n;
198  double lambda = x/p;
199  double multiplier = 1/p/(lambda + 1)/(lambda + 1);
200  double fac = 1;
201  double res = 1; /* A[0] = 1 */
202  double expfac, term;
203 
204  expfac = exp(-lambda*p)/(lambda + 1)/p;
205  if (expfac == 0) {
206  sf_error("expn", SF_ERROR_UNDERFLOW, NULL);
207  return 0;
208  }
209 
210  /* Do the k = 1 term outside the loop since A[1] = 1 */
211  fac *= multiplier;
212  res += fac;
213 
214  for (k = 2; k < nA; k++) {
215  fac *= multiplier;
216  term = fac*polevl(lambda, A[k], Adegs[k]);
217  res += term;
218  if (fabs(term) < MACHEP*fabs(res)) {
219  break;
220  }
221  }
222 
223  return expfac*res;
224 }
psi
double psi(double x)
Definition: psi.c:146
EUL
#define EUL
Definition: expn.c:63
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
Gamma
double Gamma(double x)
Definition: gamma.c:160
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
isnan
#define isnan(X)
Definition: main.h:93
res
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3
exp
const EIGEN_DEVICE_FUNC ExpReturnType exp() const
Definition: ArrayCwiseUnaryOps.h:97
boost::multiprecision::fabs
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:119
SF_ERROR_UNDERFLOW
@ SF_ERROR_UNDERFLOW
Definition: sf_error.h:11
n
int n
Definition: BiCGSTAB_simple.cpp:1
A
Definition: test_numpy_dtypes.cpp:298
MACHEP
double MACHEP
Definition: const.c:54
polevl
static double polevl(double x, const double coef[], int N)
Definition: polevl.h:65
Adegs
static const int Adegs[]
Definition: expn.h:19
expn
double expn(int n, double x)
Definition: expn.c:70
polevl.h
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
lambda
static double lambda[]
Definition: jv.c:524
expn.h
Eigen::ArrayBase::pow
const Eigen::CwiseBinaryOp< Eigen::internal::scalar_pow_op< typename Derived::Scalar, typename ExponentDerived::Scalar >, const Derived, const ExponentDerived > pow(const Eigen::ArrayBase< Derived > &x, const Eigen::ArrayBase< ExponentDerived > &exponents)
Definition: GlobalFunctions.h:143
BIG
#define BIG
Definition: expn.c:64
mconf.h
big
static double big
Definition: igam.c:119
p
float * p
Definition: Tutorial_Map_using.cpp:9
sf_error
void sf_error(const char *func_name, sf_error_t code, const char *fmt,...)
Definition: sf_error.c:41
nA
#define nA
Definition: expn.h:4
SF_ERROR_SINGULAR
@ SF_ERROR_SINGULAR
Definition: sf_error.h:10
NULL
#define NULL
Definition: ccolamd.c:609
expn_large_n
static double expn_large_n(int, double)
Definition: expn.c:194
align_3::t
Point2 t(10, 10)
MAXLOG
double MAXLOG
Definition: expn.c:65
SF_ERROR_DOMAIN
@ SF_ERROR_DOMAIN
Definition: sf_error.h:16
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9


gtsam
Author(s):
autogenerated on Sat Nov 16 2024 04:02:16