【问题标题】:return value from embedded c++ function in R从 R 中的嵌入式 C++ 函数返回值
【发布时间】:2013-06-23 21:46:05
【问题描述】:

我有一些 R 代码,有点慢,所以我一直在尝试使用“内联”库直接在 R 代码中编写一些 c++ 代码。

这很好用,我现在正在尝试调整它。

只有在 R 中分配“结果”数据结构并将它们作为函数参数传递给 c 函数时,我才能使其工作。我想知道是否有可能在 R 代码中有一个非 void c/c++ 函数,这样内存是从 c/c++ 而不是 R 分配和返回的。

请看下面的例子:

library(inline)
cppSig <- signature(res="numeric",ary="numeric",len="integer")
cppBody <- "
int lens=len[0];
res[0]=0;
  for(int j=0;j<lens;j++)
     res[0] += ary[j];
res[0] /= (double) lens;
#if 0 //Is something like this possible? 
    double *rary = new double[lens];
    for(int i=0;i<lens;i++) rary[i] = ary[i]-res[0];
    return rary;
#endif
"
cfun <- cfunction( sig=list(myMean=cppSig), 
                 body=list(cppBody),verbose=T, 
                 convention=".C", cxxargs="-O3", cppargs="-O3",language="C++")
cfunWrap <- function(x)
  cfun$myMean(res=0,ary=x,length(x))$res


cfunWrap(x=rnorm(100))

谢谢

【问题讨论】:

    标签: c++ r rcpp inline-code


    【解决方案1】:

    我会做一些不同的事情,尤其是在只是随便看看 Rcpp 文档之后。所以这里只是一个快速列表:

    1. 是的,我们可以使循环更快。经常很多。
    2. 是的,我们可以返回原子 C/C++ 类型以及向量。有很多例子。对于这些非向量类型,一种使用wrap();双精度向量会自动返回。但是你永远不会在他们身上使用new/delete。请参阅Writing R Extensions 了解原因。
    3. 是的,您可以使用内联包。我们经常使用它。但是我们从不将它与来自cfunction().C() 调用约定一起使用。 始终使用cxxfunction(),或至少启用.Call()。我不知道你是怎么错过的。
    4. 从 Rcpp 0.10.0 开始,我们有了“Rcpp 属性”,它比内联及其 cxxfunction() 更易于使用。例如,四处寻找sourceCpp()cppFunction(),甚至阅读小插图。
    5. 最后,您确实缺少一些基本的东西。您是否阅读了 pdf 小插图 Rcpp-iintroduction 和/或 Rcpp-FAQ?

    编辑: 好的,这是一个完整的示例,遵循您的函数结构(但我们可以做得更好,见下文):

    #include <Rcpp.h>
    
    using namespace Rcpp; 
    
    // [[Rcpp::export]]
    NumericVector monkey(NumericVector ary) {
      int lens = ary.length();   // objects can tell you about their length
      double res=0;
      for(int j=0;j<lens;j++) res += ary[j];
      res /= (double) lens;
    
      NumericVector rary(lens);
      for(int i=0;i<lens;i++) rary[i] = ary[i]-res;
      return rary;
    }
    
    // and we even include some R code to test automagically
    
    /*** R
    set.seed(42)
    x <- rnorm(5)   # just five to keep printout short
    monkey(x)
    cat("Check:")
    x - mean(x)
    */
    

    如果你调用它,它也会在底部运行 R 代码:

    R> Rcpp::sourceCpp('/tmp/monkey.cpp')
    
    R> set.seed(42)
    
    R> x <- rnorm(5)   # just five to keep printout short
    
    R> monkey(x)
    [1]  0.9296545 -1.0060021 -0.0781755  0.1915587 -0.0370356
    
    R> cat("Check:")
    Check:
    R> x - mean(x)
    [1]  0.9296545 -1.0060021 -0.0781755  0.1915587 -0.0370356
    R>
    

    Rcpp 的关键特性之一 是您甚至可以在 C++ 中进行向量运算:

    R> cppFunction('NumericVector monkey2(NumericVector x) { return x - mean(x); }')
    R> monkey2(x)
    [1]  0.9296545 -1.0060021 -0.0781755  0.1915587 -0.0370356
    R> 
    

    这只是编译了一个新的单行 C++ 函数,该函数对整个向量 x 进行操作并运行它。

    【讨论】:

    • 德克,鉴于?cfunction 实际上有一个将.Ccfunction 结合使用的示例,您的第3 点似乎有点苛刻......
    • @HongOoi:你可以使用cfunction().Call(),并且应该。但是你简单的不能在有限的.C() 接口上使用Rcpp。对于SEXP 交换,您必须使用.Call(),而不是.C()。内联包在 Rcpp 之前启动。我们只使用cxxfunction() 扩展(或者在旧示例中​​cfunction().Call() 接口显式调用)。根本没有别的办法。
    • @HongOoi:我稍微改写了这一点;希望现在更清楚了。 cfunction() 可以使用(尽管cxxfunction() 设置了更多正确的参数)但您必须使用.Call() 接口。或者只使用“Rcpp 属性”。
    猜你喜欢
    • 1970-01-01
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多