gsl无限积分区间的错误。找到了不良的被积累行为。怎么解决?

时间:2016-06-09 15:10:37

标签: c compiler-errors integration gsl

在尝试使用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 = &params;
    gsl_integration_qagiu (&dI2mu_u, 0, 0, 1e-7, 100000,
             w, &resultTest2, &error1Test2);

该功能有以下几个方面:

Funcion im trying to integrate在我看来,这是一种非常好的行为。因此,我不是执行无限集成,而是执行集成,直到我认为可重新定义的上限,例如:

  gsl_function G;
 G.function = &dI2dmu;
 G.params = &params;

 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”。有任何想法吗?我提前感谢您的帮助。

2 个答案:

答案 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 = &params;
    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中定义函数的方法

enter image description here

所以比较答案:

  • GSL -5.065288e-03
  • Mathematica -0.005065287633739702

答案 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

以下是xDBL_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/Ep1.0一词接近x