我正在使用针对我的问题的非常具体的模拟退火算法构建R中的包,我对C代码和SEXP有疑问,我无法解决。我不是R的专家,我一直在使用它只有3个星期......但我必须这样做。
据我所知,R中的.Call
函数通过引用将参数作为SEXP结构传递给C(即它们不重复)。我对吗?如果我在C中使用另一个需要此SEXP结构的第一个函数调用另一个函数怎么办? (见例)。我问,因为其中一个参数很大并且使用了很多空间(10 ^ 7~10 ^ 18双倍,虽然我不会在每次迭代中都使用它们)而且我会调用这个函数很多次,所以如果我每次调用它时这个参数都会重复,那么我的内存就会耗尽。
MWE:
R电话
MySimAn <- function(def_energy, i_pos, T0, Tfinal){
ret <- .Call("CMySimAn",def_energy, i_pos, T0, Tfinal, seq0)
ret
}
C函数
double Energy(SEXP def_energy, SEXP seq0, int i0){
int i;
double res=0;
for(i=0;i<INTEGER(GET_DIM(seq0))[0];i++){
res += NUMERIC(def_energy)[i0+INTEGER(seq0)[i]];
}
return(res);
}
SEXP CmySimAn(SEXP def_energy, SEXP i_pos, SEXP T0, SEXP Tfinal, SEXP seq0){
SEXP = Ene;
PROTECT(Ene = NEW_NUMERIC(1));
REAL(Ene)[0] = Energy(def_energy, seq0, INTEGER(i_pos));
UNPROTECT(1);
return Ene;
}
这样的事情是否有效(函数Energy
中的代码未被检查,因此可能是错误的)?每当我调用它时,我是否会创建def_energy的副本,无论是在R还是C?非常感谢你的帮助。
答案 0 :(得分:8)
代码几乎(语法上)正确写入,并且没有内存复制;从R传递给C的参数应该被视为“只读”。
一个常见的范例是编写一个R / C接口层,在纯(非R)C中从该层调用任何函数。所以
double Energy(const double *def_energy, const int *seq0, int dim0, int i0)
{
int i;
double res=0;
for(i = 0; i < dim0; i++) {
res += def_energy[i0 + seq0[i]];
}
return(res);
}
使用const
强制执行隐式契约,不应写入从R传递的值。使用R / C包装器
SEXP CmySimAn(SEXP def_energy, SEXP i_pos, SEXP T0, SEXP Tfinal, SEXP seq0){
double Ene = Energy(REAL(def_energy), INTEGER(seq0), INTEGER(GET_DIM(seq0)[0]),
INTEGER(i_pos)[0]);
return ScalarReal(Ene);
}
数字元素的访问者是REAL()
(您在Energy中使用了NUMERIC
)。您对PROTECT(...); REAL(Ene)[0] = ...; UNPROTECT(Ene);
的使用是正确的。