如何在Rcpp中以数字方式计算积分

时间:2015-02-07 05:41:50

标签: rcpp integral

我已经搜索了一个小时来进行数值积分的方法。我是Rcpp的新手,现在重写我的旧程序。我在R做过的是:

   x=smpl.x(n,theta.true)   
   joint=function(theta){# the joint dist for
                         #all random variable
     d=c()
     for(i in 1:n){
       d[i]=den(x[i],theta)
     }
     return(prod(d)*dbeta(theta,a,b))   }  
 joint.vec=Vectorize(joint)##vectorize the function, as required when
                           ##using integrate()   
margin=integrate(joint.vec,0,1)$value # the
                                ##normalizeing constant at the donominator  
 area=integrate(joint.vec,0,theta.true)$value # the values at the
                                              ## numeritor
  • R中的integrate()函数速度很慢,而且由于我正在对大小为n的样本的后验分布进行积分,因此积分的值会很大而且误差很大。
  • 我试图在Rcpp的帮助下重写我的代码,但我不知道如何处理集成。我应该加c++ h file吗?还是有什么建议吗?

2 个答案:

答案 0 :(得分:0)

您可以在C中对自己的功能进行编码,然后通过sourceCpp功能调用它,然后在integrate中调用R。或者,您可以使用R的{​​{1}}宏在C代码中调用Function的集成功能。有关如何从Rcpp调用R函数的示例,请参见第56页的Dirk的书(无缝R和C ++与Rcpp的集成)。另一种替代方案(我认为对大多数情况来说是最好的)是使用C包将C中编写的函数直接集成到C中。

关于巨大的归一化常数,有时最好在积分之前在模式下缩放函数(您可以找到具有RcppGSLnlminb等模式的模式。然后,集成重新调整的函数并恢复原始的nroming常量,将得到的归一化常数乘以重新缩放因子。希望这可能有所帮助!

答案 1 :(得分:0)

在阅读了你的@utobi建议之后,我觉得我自己的编程可能更容易。我只是使用辛普森公式来近似积分:

// [[Rcpp::export]]
double den_cpp (double x, double theta){
return(2*x/theta*(x<=theta)+2*(1-x)/(1-theta)*(theta<x));
}
// [[Rcpp::export]]
double joint_cpp ( double theta,int n,NumericVector x, double a, double b){
double val = 1.0;
NumericVector d(n);
for (int i = 0; i < n; i++){
double tmp = den_cpp(x[i],theta);
val = val*tmp;
}
val=val*R::dbeta(theta,a,b,0);
return(val);
}
// [[Rcpp::export]]
List Cov_rate_raw ( double theta_true,  int n, double a, double b,NumericVector x){
//This function is used to test, not used in the fanal one
int steps = 1000;
double s = 0;
double start = 1.0e-4;
std::cout<<start<<" ";
double end = 1-start;
std::cout<<end<<" ";
double h = (end-start)/steps;
std::cout<<"1st h ="<<h<<" ";
double area = 0;
double margin = 0;
for (int i = 0; i < steps ; i++){
double at_x = start+h*i;
double f_val = (joint_cpp(at_x,n,x,a,b)+4*joint_cpp(at_x+h/2,n,x,a,b)+joint_cpp(at_x+h,n,x,a,b))/6;
s = s + f_val;
}
margin = h*s;
s=0;
h=(theta_true-start)/steps;
std::cout<<"2nd h ="<<h<<" ";
for (int i = 0; i < steps ; i++){
double at_x = start+h*i;
double f_val = (joint_cpp(at_x,n,x,a,b)+4*joint_cpp(at_x+h/2,n,x,a,b)+joint_cpp(at_x+h,n,x,a,b))/6;
s = s + f_val;
}
area = h * s;
double r = area/margin;
int cover = (r>=0.025)&&(r<=0.975);
List ret;
ret["s"] = s;
ret["margin"] = margin;
ret["area"] = area;
ret["ratio"] = r;
ret["if_cover"] = cover;
return(ret);
}

我对c ++并不擅长,所以两个 for 循环就像傻了。

它通常有效,但仍有几个潜在的问题:

  1. 我真的不知道如何选择步骤,或者我需要多少个子间隔来近似积分。当我还是本科生时,我已经进行了数值分析,我想也许我需要查看关于错误术语表达的书,以确定步长。
  2. 我将结果与来自R的结果进行了比较.R中的integrate()函数可以处理区间[0,1]上的积分。这对我有帮助,因为我的函数未定义为0或1,这需要无限的值。在我的C ++代码中,我只能从[1e-4,1-1e-4]开始我的间隔。我尝试了不同的值,如1e-7,1e-10,然而,1e-4是最接近R的结果......我应该怎么做呢?