我在哪里可以学习如何编写C代码来加速较慢的R函数?

我在哪里可以学习如何编写C代码来加速较慢的R函数?,r,rcpp,R,Rcpp,学习如何编写与R一起使用的C代码的最佳资源是什么?我知道R扩展的部分,但我觉得这很难。写C代码与R一起使用的好资源(在线和离线)是什么 为了澄清,我不想学习如何编写C代码,我想学习如何更好地集成R和C。例如,如何从C整数向量转换为R整数向量(或反之亦然),或如何从C标量转换为R向量?好吧,这是一个很好的老用法源代码,Luke!——R本身有很多(非常有效的)C代码可以学习,而CRAN有数百个包,其中一些来自您信任的作者。这提供了真实的、经过测试的例子供研究和改编 但是,正如Josh所怀疑的,我倾向

学习如何编写与R一起使用的C代码的最佳资源是什么?我知道R扩展的部分,但我觉得这很难。写C代码与R一起使用的好资源(在线和离线)是什么


为了澄清,我不想学习如何编写C代码,我想学习如何更好地集成R和C。例如,如何从C整数向量转换为R整数向量(或反之亦然),或如何从C标量转换为R向量?

好吧,这是一个很好的老用法源代码,Luke!——R本身有很多(非常有效的)C代码可以学习,而CRAN有数百个包,其中一些来自您信任的作者。这提供了真实的、经过测试的例子供研究和改编

但是,正如Josh所怀疑的,我倾向于C++,因此。它也有很多例子

编辑:我发现有两本书很有用:

  • 第一个版本是Venables和Ripley的“s Programming”,尽管它的时间越来越长(多年来一直有传言说会有第二个版本)。当时没有别的东西
  • 第二次在室中的“数据分析软件”,这是最近更近,并有更好的R中心的感觉-和两个章节上延伸C和C++的R。另外,约翰因为我所做的事而把我撕成碎片,所以单凭这一点就值得入场费

约翰说,当他发现R对象和C++对象(VAS)之间的匹配非常自然时,他就越来越喜欢(并且做出贡献)。 <编辑2:哈德利的重提问题,我强烈敦促你考虑C++。C语言中有太多的陈词滥调——非常乏味,而且是可以避免的。看一看这张照片。另一个简单的例子是,我展示了,而不是担心10%个差异(在RADFED尼尔例子之一),我们可以得到八倍的增加与C++(当然是一个捏造的例子)。 <>编辑3:你可能会碰到C++错误,这是一个很难理解的问题。但是仅仅使用Rcpp而不是扩展它,您几乎不需要它。虽然这个代价是不可否认的,但它被简单代码、更少的样板、没有保护/不保护、没有内存管理等PPP的影响远远地遮蔽了。道格贝茨昨天声明他发现C++和Rcpp更像写R而不是编写C++。YMMV和所有这些。

哈德利

<>你可以写C++代码,类似于C代码。 我理解C++所说的比C更复杂的内容。这是如果你想掌握一切:对象、模板、STL、模板元编程等等…大多数人不需要这些东西,只能依靠别人去做。Rcpp的实现非常复杂,但仅仅因为你不知道冰箱是如何工作的,这并不意味着你不能开门去抓新鲜牛奶

从您对R的许多贡献中,让我印象深刻的是,您发现R有些乏味(数据处理、图形、字符串处理等…)。我们准备使用R的内部C API来应对更多的惊喜。这是非常乏味的

我不时地阅读R-exts或R-ints手册。这很有帮助。但大多数时候,当我真的想了解一些东西时,我会进入R源代码,以及由例如Simon编写的包的源代码(那里通常有很多东西需要学习)


Rcpp旨在消除API中这些繁琐的方面

你可以自己判断你发现什么更复杂,更模糊,等等。。。基于几个例子。此函数使用C API创建字符向量:

SEXP foobar(){
  SEXP ab;
  PROTECT(ab = allocVector(STRSXP, 2));
  SET_STRING_ELT( ab, 0, mkChar("foo") );
  SET_STRING_ELT( ab, 1, mkChar("bar") );
  UNPROTECT(1);
}
使用Rcpp,您可以编写与以下相同的函数:

SEXP foobar(){
   return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}
或:

正如德克所说,这几个小插曲还有其他例子。我们通常也会将人们引向我们的单元测试,因为每个单元测试都测试代码的一个非常特定的部分,并且在某种程度上是不言自明的

我在这里显然有偏见,但我建议大家熟悉Rcpp,而不是学习R的C API,如果Rcpp有什么不清楚或不可行的地方,就来看看邮件列表

不管怎么说,推销结束了

我想这完全取决于你最终想写什么样的代码


罗曼:没错。Rcpp类实现了一些接近RAII模式的东西。创建Rcpp对象时,构造函数会采取适当的措施确保底层R对象(SEXP)受到垃圾收集器的保护。析构函数撤消保护。这在小插曲中有解释。底层实现依赖于R API函数R_PreserveObjectR_ReleaseObject

由于C++封装,确实存在性能损失。我们试图通过内联等将这一点保持在最低限度。。。代价很小,当您考虑到编写和维护代码所需时间方面的收益时,就没有那么重要了

从Rcpp类函数调用R函数比使用C api直接调用eval慢。这是因为我们采取预防措施并将函数调用封装到Trycatch块中,这样我们就可以捕获R错误并将它们推广到C++异常,以便使用C++中的标准TIG/catch来处理它们。p>
大多数人希望使用向量(特别是NumericVector),这个类的代价很小。examples/convalvebenchmarks目录包含来自R-exts的臭名昭著的卷积函数的几个变体,vignette具有基准测试结果。事实证明,Rcpp使它比使用R API的基准代码更快SEXP foobar(){ Rcpp::CharacterVector res(2) ; res[0] = "foo" ; res[1] = "bar" ; return res ; }
#include <Rcpp.h>

RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;
SEXP foo( SEXP x1, SEXP x2 ){
   ...
}
 SEXP foo( SEXP x_) {
    Rcpp::NumericVector x( x_ ) ;
    ...
 }
 Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
 Rcpp::NumericVector x = Rcpp::NumericVector::create( 
    _["a"] = 1.0, 
    _["b"] = 2.0, 
    _["c"] = 3
 ) ;
 Rcpp::NumericVector x( 10 ) ;      // filled with 0.0
 Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0
SEXP sum( SEXP x_ ){
   Rcpp::NumericVector x(x_) ;
   double res = 0.0 ;
   for( int i=0; i<x.size(), i++){
      res += x[i] ;
   }
   return Rcpp::wrap( res ) ;
}
using namespace Rcpp ;
SEXP sum( SEXP x_ ){
   NumericVector x(x_) ;
   double res = sum( x ) ;
   return wrap( res ) ;
}