Rcpp的前世此生
本年六月,Springer useR系列新出了一本,Seamless R and C++ Integration with Rcpp,
这大概是的一本Rcpp完整教程。Rcpp险些可以认为是R语言的一个里程碑,而其较大的特点就是那本书标题里的谁人词“Seamless”。R自己
自带了C语言接口,但并不是那么好用,尤其是涉及内存打点的时候,而Rcpp乐成的办理了这个问题,实现了“无缝链接”。
Rcpp作者们
既然说了Rcpp是R语言的一个里程碑,我们先看看Rcpp的作者们,这险些是现有最强大的一个package团队。下面凭据Rcpp网站上的顺序依次先容。
Dirk Eddelbuettel
Rcpp此刻的主要维护者之一,就是Springer那本书的作者,Ketchum Trading公司高级量化阐明师,资深quant。Dirk是Debian/Ubuntu下R的维护者,R/Finance集会会议提倡人之一,其小我私家博客上有历次集会会议上陈诉的slide,R社区重要技能网站之一。
Romain Francois
Rcpp此刻的主要维护者之一,独立的R开拓者和咨询师,自我认定是“Professional R Enthusiast”,其博客也是圈内重要技能博客之一。
Douglas Bates
Rcpp作者之一,Wisconsin-Madison大学统计系荣休传授,bioconductor首创人。
John Chambers
S语言的缔造者,现为Stanford大学参谋传授,美国统计学会院士,R语言焦点团队成员之一。Chambers于1998因S语言得到ACM Software System Award,这是软件界较高奖项之一,1999年授予Apache Group,1995年授予World Wide Web。
JJ Allaire
RStudio首创人,著名的ColdFusion东西和Windows Live Writer也是其作品之一。
Rcpp大事记
2005年,Rcpp作为RQuantlib的一部门呈现,作者为Dominick Samperi;
2006年,Rcpp在CRAN上宣布,后改名为RcppTemplate;
2008年,Dirk抉择重写Rcpp,并连续宣布新版本,老版本API作为RcppClassic继承开拓维护;
2009年,RcppTemplate正式放弃维护,进入CRAN存档;
2009年,Dirk和Franois从头设计Rcpp,并宣布新版本;
2013年,CRAN中基于Rcpp开拓的package已高出100个。
Rcpp实例
这里用的是Dirk书中的一个很简朴的例子:Fibonacci数列。这玩意太简朴了,我们直接看代码就好了。
假如用R写,很简朴的一个实现如下:
fibR<-function(n){
first <- 0
second <- 1
third <- 0
for(i in seq_len(n)){
third <- first + second
first <- second
second <- third
}
return(first)
}
C++的实现如下,其实和普通的C++对比,只是多了一个范例转换罢了。个中SEXP是pointer to S expression
type,这个是指向R各类范例的一个指针。我不知道列位对“指针”什么情感,横竖听到这两个字,假如再涉及内存打点,我就有一个生理性的惊骇,而
Rcpp的伟大之处就在于办理了这个问题,这个后头会提到。
#include
int fib(const int x){
int first = 0;
int second = 1;
int third = 0;
for(int i = 1; i <= x; i++){
third = first + second;
first = second;
second = third;
}
return first;
}
extern "C" SEXP fibWrapper(SEXP xs){
int x = Rcpp::as(xs);
int result = fib(x);
return (Rcpp::wrap(result));
}
编译C++文件从而可以或许让R挪用的要领一般有两种,假如在Linux情况下,配置情况变量,呼吁如下:
$ export PKG_LIBS=`Rscript -e "Rcpp:::LdFlags()"`
$ export PKG_CXXFLAGS=`Rscript -e "Rcpp:::CxxFlags()"`
$ R CMD SHLIB myfile.cpp
尚有一种跨平台的要领,windows下只要配置好情况变量也没问题的玩法:
$ Rscript -e "Rcpp:::SHLIB('myfile.cpp')"
其实只要看一下输出功效,就大白了,其实本身手动写完整的呼吁也不是不可
$ Rscript -e "Rcpp:::SHLIB('fibWrapper.cpp')"
$ g++ -I/usr/share/R/include -DNDEBUG -I/home/kouqiang/R/x86_64-pc-linux-gnu-library/3.0/Rcpp/include -fpic -O3 -pipe -g -c fibWrapper.cpp -o fibWrapper.o
$ g++ -shared -o fibWrapper.so fibWrapper.o -L/home/kouqiang/R/x86_64-pc-linux-gnu-library/3.0/Rcpp/lib -lRcpp -Wl,-rpath,/home/kouqiang/R/x86_64-pc-linux-gnu-library/3.0/Rcpp/lib -L/usr/lib/R/lib -lR
R里挪用照旧老步伐:
dyn.load("fibWrapper.so")
.Call("fibWrapper",10)
## [1] 55
Rcpp的优势
Rcpp可以被成为“无缝链接”的原因,我小我私家认为就两个,一个是省去了内存打点的贫苦,一个是inline要领。
内存打点
当初最早看到Rcpp的时候,Dirk也是用的这个例子。从这点来看,他真的不会忽悠。这个例子完全没有突出Rcpp的优势,因为用R自带的C语言API,写出来也根基就这个样子。
#p#分页标题#e#
从我小我私家角度来看,Rcpp较大的创举在于办理了内存打点问题。假如列位本身用C写过R
package,可能看过一些package甚至R语言的源代码,PROTECTED和UNPROTECTED两个宏应该会常常见到的。由于R系统对内存
的打点,假如分派的内存不被掩护起来,很有大概会被接纳掉。R和C直接举办数据传输,必需利用指针,无论是SEXP照旧直接声明的指针。在举办计较时,如
果本成分派了内存空间,也必需举办掩护。下面贴了个比拟的例子,各人看看就大白了。
//R自带的C API版本,留意PROTECTED和UNPROTECTED
#include
#include
extern "C"SEXP vectorfoo(SEXP a, SEXP b){
int i, n;
double *xa, *xb, *xab; SEXP ab;
PROTECT(a = AS_NUMERIC(a));
PROTECT(b = AS_NUMERIC(b));
n = LENGTH(a);
PROTECT(ab = NEW_NUMERIC(n));
xa=NUMERIC_POINTER(a); xb=NUMERIC_POINTER(b);
xab = NUMERIC_POINTER(ab);
double x = 0.0, y = 0.0 ;
for (i=0; i ;>
//Rcpp版本
#include
SEXP foo( SEXP xs, SEXP ys ){
Rcpp::NumericVector xx(xs), yy(ys) ;
int n = xx.size() ;
Rcpp::NumericVector res( n ) ;
double x = 0.0, y = 0.0 ;
for (int i=0; i ;>
这几多是个有点繁琐的工作,而Rcpp自动完成了这一步,也就是说,利用了Rcpp,用户不需要再思量内存的问题,只要通过Rcpp举办数据转换就
足够了。可以说,现有的C++代码,不需要举办几多修改,就可以被R挪用,这也是我认为Rcpp是个里程碑级别成绩的主要原因。
inline
固然说,Rcpp已经足够利便了,但照旧要写一个C++文件,编译之后再举办挪用,而面比拟力简短的C++代码时,这几多有点小题大作了,所以就有了inline。这里的inline和C内里的“内联函数”很雷同,照旧看Fibonacci数列的例子。
library(inline)
fib <- cxxfunction(signature(xs="int"),
plugin="Rcpp",
body='
int n = Rcpp::as(xs);
int first = 0;
int second = 1;
int third = 0;
for(){
third = first + second;
first = second;
second = third;
}
return first;
')
这样我们就界说了一个inline函数,在R里运行这段代码就足够了,而编译挪用等工作,完全被封装了起来。所谓“无缝”,也就如此吧。
最后
这里只聊了Rcpp最简朴的一个方面,并且许多对象都略过,好比inline里的plugin等。只是但愿各人能对Rcpp的优势有一个直接的认识,更多的细节,各人有乐趣照旧去看Dirk的书吧。