For my research, I need to integrate the following function:
$$ W(z)=\int_0^{\infty}dx\ w(x,z)\\ =\int_0^{\infty}dx\frac{e^x}{(e^x+1)^2}\log{\left(\frac{e^{z^2/4x+x}+1}{e^{z^2/4x+x}-e^x}\right)}\\ =\int_0^{\infty}dx\frac{e^x}{(e^x+1)^2}\log{\left(\frac{e^{z^2/4x}+e^{-x}}{e^{z^2/4x}-1}\right)} $$
where $z > 0$. The numerical integration of this function is part of a larger code, where the results of $W(z)$ are used as input for other functions. So far, I have written the integrand as
double integrand__W(double x, double z){
double arg = z*z/(4.0*x);
double num = exp(arg+x)+1;
double den1 = expm1(arg);
double den2 = exp(x);
num = isinf(num) ? arg+x : log(num);
den1 = isinf(den1) ? arg : log(den1);
den2 = x; //log(exp(x))=x
double t1 = num-den1-den2;
num = exp(x);
double den = exp(x)+1;
double t2 = isinf(den) ? exp(-x) : num/(den*den);
return t1*t2;
}
and its plot is shown below:
For numerical integration, I'm using Cubature, a simple C-package for adaptive multidimensional integration:
//integrator
struct fparams {
double z;
};
int inf_W(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval){
struct fparams * fp = (struct fparams *)fdata;
double z = fp->z;
double t = x[0];
double aux = integrand__W(a_int+t*pow(1.0-t, -1.0), z)*pow(1.0-t, -2.0);
if (!isnan(aux) && !isinf(aux))
{
fval[0] = aux;
}
else
{
fval[0] = 0.0;
}
return 0;
}
//range integration 1D
size_t maxEval = 1e7;
double xl[1] = { 0 };
double xu[1] = { 1 };
double W, W_ERR;
struct fparams params = {z};
hcubature(1, inf_W, ¶ms, 1, xl, xu, maxEval, 0, 1e-5, ERROR_INDIVIDUAL, &W, &W_ERR);
cout << "z: " << z << " | " << W << " , " << W_ERR << endl;
where the integration over the semi-infinite interval is possible by a change of variables:
$$ \int_a^{\infty}f(x)dx=\int_0^1 f\left(a+\frac{t}{1-t}\right)\frac{1}{(1-t)^2}dt $$
Analytically, I know that $w(x,z)$ is non-negative, so the integral itself should be non-negative. However, I'm getting some incorrect results due to a lack of accuracy:
z: 100 | -3.97632e-17 , 1.24182e-16
In Mathematica
, working with high precision, I can get the desired result:
w[x_, z_] := E^x/(E^x + 1)^2 Log[(E^(z^2/(4 x)) + E^-x)/(E^(z^2/(4 x)) - 1)]
W[z_?NumericQ] := NIntegrate[w[x, z], {x, 0, ∞},
WorkingPrecision -> 40,
Method -> "LocalAdaptive"]
W[100]
(* 4.679853458969239635780655689865016458810*10^-43 *)
So far, I have heard two possible diagnostics regarding this issue:
- The integrand is very small for large $z$ and high precision is required in the integration.
- The integration scheme permits negative weights, sometimes resulting in possibly higher accuracy for integration, but here is causing the false negatives.
My question: Any ideas about how to fix this issue, either by rewriting my integrand such that I can reach the required precision or switching to a different integration scheme? I need to solve this integral within my code, so using Mathematica
is not an option.
t1=log1p((exp(-x)+1)/expm1(arg))
? $\endgroup$