Rcpp的前世此生
当前位置:以往代写 > 其他教程 >Rcpp的前世此生
2019-06-14

Rcpp的前世此生

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的书吧。

    关键字:

在线提交作业