在尝试使用C中的GSL对infinte区间[0,inf]进行数值积分后,我收到以下错误消息。
gsl: qags.c:553: ERROR: bad integrand behavior found in the integration interval
Default GSL error handler invoked.
Command terminated by signal 6
这是我正在整合的功能 $
double dI2dmu(double x, void * parametros){
double *p,Ep,mu,M,T;
p=(double *) parametros;
M=p[0];
T=p[1];
mu=p[2];
Ep=sqrt(x*x+M*M);
double fplus= -((exp((Ep - mu)/T)/(pow(1 + exp((Ep - mu)/T),2)*T) - exp((Ep + \
mu)/T)/(pow(1 + exp((Ep + mu)/T),2)*T))*pow(x,2))/(2.*Ep*pow(PI,2));
return fplus;
}
整合程序的代码
params[0]=0.007683; //M
params[1]=0.284000;// T
params[2]=0.1; //mu
gsl_function dI2mu_u;
dI2mu_u.function = &dI2dmu;
dI2mu_u.params = ¶ms;
gsl_integration_qagiu (&dI2mu_u, 0, 0, 1e-7, 100000,
w, &resultTest2, &error1Test2);
该功能有以下几个方面:
在我看来,这是一种非常好的行为。因此,我不是执行无限集成,而是执行集成,直到我认为可重新定义的上限,例如:
gsl_function G;
G.function = &dI2dmu;
G.params = ¶ms;
gsl_integration_qags (&G, 0, 1e2*A, 0, 1e-7, 100000,
w, &result1, &error1);
获得与Mathematica无限集成结果一致的结果
result definite up to 10*A = 0.005065263943958745
result up to infinity = nan
Mathematica result up to infinity = 0.005065260000000000
但GSL无限积分keps是“nan”。有任何想法吗?我提前感谢您的帮助。
答案 0 :(得分:1)
我认为这里的问题是与Mathematica不同,C在计算中不使用任意精度。然后,在计算Exp [Ep]的某个时刻,数值计算溢出。
现在,GSL使用变换x =(1-t)/ t来映射到区间(0,1)。 因此,因为对于极值而言,函数的行为倾向于不确定(0/0或inf / inf等),因此t< 0可以获得nan结果。 也许如果你写出条款
Exp [(Ep(x) - \ Mu)/ T] / {1 + Exp [(Ep(x) - \ Mu)/ T]} ^ 2
使用A / B = Exp [Ln A - Ln B],您可以获得更好的数值行为。
我会尝试,如果我有好结果,那么我会告诉你。
解决方案
正如我之前所说,你必须注意不确定形式所带来的问题。因此,让我们使用对数版本写出有问题的术语:
double dIdmu(double x, void * parametros){
double *p,Ep,mu,M,T;
p=(double *) parametros;
M=p[0];
T=p[1];
mu=p[2];
Ep=sqrt(x*x+M*M);
double fplus= - ( exp( (Ep - mu)/T -2.0*log(1.0 + exp((Ep - mu)/T) ) ) - exp( (Ep + mu)/T -2.0*log(1.0 + exp((Ep + mu)/T) ) ) ) * pow(x,2) / (2.* T * Ep*pow(M_PI,2));
return fplus;
}
并使用此主要功能
int main()
{
double params[3];
double resultTest2, error1Test2;
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (10000);
params[0]=0.007683; //M
params[1]=0.284000;// T
params[2]=0.1; //mu
gsl_function dI2mu_u;
dI2mu_u.function = &dIdmu;
dI2mu_u.params = ¶ms;
gsl_integration_qagiu (&dI2mu_u, 0.0, 1e-7, 1e-7, 10000, w, &resultTest2, &error1Test2);
printf("%e\n", resultTest2);
gsl_integration_workspace_free ( w);
return 0;
}
你得到了答案: -5.065288e-03。 我很好奇......这就是我在Mathematica中定义函数的方法
所以比较答案:
答案 1 :(得分:1)
正如@yonatan zuleta ochoa指出的那样,问题出在.active{
background: linear-gradient(#821e82, #be5abe);
}
。对于exp(t)/pow(exp(t)+1,2)
的{{1}},exp(t)
DBL_MAX
的{{1}}值t
nextafter(log(DBL_MAX), INFINITY)
,~7.09783e2
exp(t) == INFINITY
可能会溢出ieee754 exp(t)/pow(exp(t)+1,2) == ∞/pow(∞+1,2) == ∞/∞ == NAN
。
exp(t)/pow(exp(t)+1,2) == exp(log(exp(t)) - log(pow(exp(t)+1,2)))
== exp(t - 2*log(exp(t)+1))
== exp(t - 2*log1p(exp(t))) //<math.h> function avoiding loss of precision for log(exp(t)+1)) if exp(t) << 1.0
时,
NAN
Yonatan提出的解决方案是使用对数,可以按如下方式进行:
t
这是一种完全合理的方法,可以避免t == (Ep ± mu)/T
达到非常高的INFINITY
值。但是,在您的代码中,如果abs(T) < 1.0
的{{1}}值接近x
,则DBL_MAX
可以是x
,即使t - 2*log1p(exp(t))
是不无限。在这种情况下,减法∞ - ∞
会变为NAN
,再次为exp(x)/pow(exp(x)+1,2)
。
另一种方法是将1.0/(pow(exp(x)+1,2)*pow(exp(x), -1))
替换为exp(x)
,将分母和分子除以x
(对于任何有限1.0/(exp(x)+exp(-x)+2.0)
都不为零)。这简化为NAN
。
以下是x
值DBL_MAX
的函数避免static double auxfun4(double a, double b, double c, double d)
{
return 1.0/(a*b+2.0+c*d);
}
double dI2dmu(double x, void * parametros)
{
double *p = (double *) parametros;
double invT = 1.0/p[1];
double Ep = hypot(x, p[0]);
double muexp = exp(p[2]*invT);
double Epexp = exp(Ep*invT);
double muinv = 1.0/muexp;
double Epinv = 1.0/Epexp;
double subterm = auxfun4(Epexp, muinv, Epinv, muexp);
subterm -= auxfun4(Epexp, muexp, Epinv, muinv);
double fminus = subterm*(x/Ep)*invT*(0.5/(M_PI*M_PI))*x;;
return -fminus;
}
的实现:
hypot(x,M)
此实现还使用sqrt(x*x, M*M)
而不是x*x
,并通过将乘法/除法的顺序重新排列到组x/Ep
来避免计算hypot(x,M)
。由于abs(x)
的{{1}}为abs(x) >> abs(M)
,因此对于较大的x/Ep
,1.0
一词接近x
。