I have been trying to compute this integral
∫∞−∞e−x21+ae−xdx
quickly and to a high-degree of accuracy.
I have some partial results, for example for n∈N
1√π∫∞−∞e−x21+e−(x+n/2)dx=122n∑i=0(−1)ie−i(2n−i)/4,
and for a∈(0,1) we have
1√π∫∞0e−x21+ae−xdx=12∞∑n=0(−1)nanen2/4erfc(n/2)
where erfc is the error function complement fuction
erfc(x)=1−erf(x),
which we obtain by using the substitution
11+ae−x=∞∑n=0(−1)nane−nx.
This erfc series does not converge very quickly unless a is very small, and wolframalpha can compute the integral very accurately between say −100 and 100 for various values of a, so I must be missing a trick.
Edit
I found an infinite series for the whole integral, but it converges slowly
1√π∫∞−∞e−x21+e−(x+a)dx=e−a22[∞∑n=0(−1)nerfcx(−a+n/2)+∞∑n=1(−1)n+1erfcx(a+n/2)],
where erfcx is the scaled complement error function
erfcx(x)=ex2erfcx(x)=ex2(1−erf(x)).
Answer
Since your integrand is bell-shaped and there are no singularities for a>0, then the Euler-Maclaurin expansion shows that simple trapezoidal quadrature converges exponentially fast.
Using this code, I was able to evaluate your integral to float precision in 17 integrand evaluations, to double in 33 evaluations, long double in 65, and 50 binary digits in 260. Doubling of the number of correct digits by halving h is observed.
Assuming that your integrand takes 100ns to evaluate, this implies that you can compute your integral to double precision in ~3.3 microseconds.
Here's the code I used
Real a = 2;
auto f = [&](Real t) { return exp(-t*t)/(1+a*exp(-t)); };
Real t_max = sqrt(-log(std::numeric_limits::epsilon()));
Real Q = boost::math::trapezoidal(f, -t_max, t_max, tol);
std::cout << "Q = " << Q << std::endl;
You presumably are using a different programming environment, but the trapezoidal rule is simple enough to code that this shouldn't be a problem.
No comments:
Post a Comment