我一直在编写R函数来计算某些分布的积分,请参阅下面的代码。
EVofPsi = function(psi, probabilityMeasure, eps=0.01, ...){
distFun = function(u){
probabilityMeasure(u, ...)
}
xx = yy = seq(0,1,length=1/eps+1)
summand=0
for(i in 1:(length(xx)-1)){
for(j in 1:(length(yy)-1)){
signPlus = distFun(c(xx[i+1],yy[j+1]))+distFun(c(xx[i],yy[j]))
signMinus = distFun(c(xx[i+1],yy[j]))+distFun(c(xx[i],yy[j+1]))
summand = c(summand, psi(c(xx[i],yy[j]))*(signPlus-signMinus))
}
}
sum(summand)
}
它工作正常,但速度很慢。通常会听到用C ++等编译语言对函数进行重新编程会加快速度,特别是因为上面的R代码涉及双循环。我也是,使用Rcpp:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double EVofPsiCPP(Function distFun, Function psi, int n, double eps) {
NumericVector xx(n+1);
NumericVector yy(n+1);
xx[0] = 0;
yy[0] = 0;
// discretize [0,1]^2
for(int i = 1; i < n+1; i++) {
xx[i] = xx[i-1] + eps;
yy[i] = yy[i-1] + eps;
}
Function psiCPP(psi);
Function distFunCPP(distFun);
double signPlus;
double signMinus;
double summand = 0;
NumericVector topRight(2);
NumericVector bottomLeft(2);
NumericVector bottomRight(2);
NumericVector topLeft(2);
// compute the integral
for(int i=0; i<n; i++){
//printf("i:%d \n",i);
for(int j=0; j<n; j++){
//printf("j:%d \n",j);
topRight[0] = xx[i+1];
topRight[1] = yy[j+1];
bottomLeft[0] = xx[i];
bottomLeft[1] = yy[j];
bottomRight[0] = xx[i+1];
bottomRight[1] = yy[j];
topLeft[0] = xx[i];
topLeft[1] = yy[j+1];
signPlus = NumericVector(distFunCPP(topRight))[0] + NumericVector(distFunCPP(bottomLeft))[0];
signMinus = NumericVector(distFunCPP(bottomRight))[0] + NumericVector(distFunCPP(topLeft))[0];
summand = summand + NumericVector(psiCPP(bottomLeft))[0]*(signPlus-signMinus);
//printf("summand:%f \n",summand);
}
}
return summand;
}
我很高兴,因为这个C ++函数运行正常。但是,当我测试这两个函数时,C ++运行了SLOWER:
sourceCpp("EVofPsiCPP.cpp")
pFGM = function(u,theta){
u[1]*u[2] + theta*u[1]*u[2]*(1-u[1])*(1-u[2])
}
psi = function(u){
u[1]*u[2]
}
print(system.time(
for(i in 1:10){
test = EVofPsi(psi, pFGM, 1/100, 0.2)
}
))
test
print(system.time(
for(i in 1:10){
test = EVofPsiCPP(psi, function(u){pFGM(u,0.2)}, 100, 1/100)
}
))
那么,有什么样的专家愿意解释我这个吗?我是否像猴子一样编码,有没有办法加快这个功能?而且,我还有第二个问题。实际上,我可以用SEXP替换输出类型double,并且SEXP的参数类型也是函数,它似乎没有改变任何东西。那有什么区别?
非常感谢您提前, 吉尔达斯
答案 0 :(得分:10)
其他人已在评论中回答。所以我只想强调一点:回调R函数很昂贵,因为我们需要对错误处理格外谨慎。只是在C ++中使用循环并调用R函数不会在C ++中重写代码。尝试重写psi
和pFGM
作为C ++函数,并在此处报告发生的情况。
你可能会说你失去了一些灵活性,而你又无法使用任何R功能。对于这样的情况,我建议使用某种混合解决方案,其中您已经实现了C ++中最常见的情况,否则回退到R解决方案。
至于另一个问题,SEXP
是一个R对象。这是R API的一部分。它可以是任何东西。当你从它创建一个Function
时(正如你在创建一个带有Function
参数的函数时隐式完成的那样),你可以保证这确实是一个R函数。开销很小,但代码表现力的增加是巨大的。