好的,我知道答案,但受到这个问题的启发,我想对以下内容得到一些好的看法:为什么下面的Rcpp练习是ca. 比内置的快15%(对于长向量)exp()?我们都知道Rcpp是R/C API的包装器,所以我们应该期待性能略差一些.
Rcpp::cppFunction("
NumericVector exp2(NumericVector x) {
NumericVector z = Rcpp::clone(x);
int n = z.size();
for (int i=0; i<n; ++i)
z[i] = exp(z[i]);
return z;
}
")
library("microbenchmark")
x <- rcauchy(1000000)
microbenchmark(exp(x), exp2(x), unit="relative")
## Unit: relative
## expr min lq median uq max neval
## exp(x) 1.159893 1.154143 1.155856 1.154482 0.926272 100
## exp2(x) 1.000000 1.000000 1.000000 1.000000 1.000000 100
Run Code Online (Sandbox Code Playgroud)
基地R倾向于做更多的检查,NA所以我们可以通过不这样做赢得一点.另请注意,通过像循环展开这样的技巧(如在Rcpp Sugar中所做的那样),我们可以做得更好.
所以我补充道
Rcpp::cppFunction("NumericVector expSugar(NumericVector x) { return exp(x); }")
Run Code Online (Sandbox Code Playgroud)
并且我得到了进一步的收益 - 用户方面的代码更少:
R> microbenchmark(exp(x), exp2(x), expSugar(x), unit="relative")
Unit: relative
expr min lq mean median uq max neval
exp(x) 1.11190 1.11130 1.11718 1.10799 1.08938 1.02590 100
exp2(x) 1.08184 1.08937 1.07289 1.07621 1.06382 1.00462 100
expSugar(x) 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 100
R>
Run Code Online (Sandbox Code Playgroud)
如果您确实希望获得性能改进,则必须编写代码以利用底层硬件并发性.你可以使用RcppParallel包装来做到这一点,parallelFor它将是一个理想的容器.
您还可以尝试更现代的实现R/C++.下一个版本Rcpp11,在几天内发布将自动加入螺纹糖,使得expSugar从之前的答案更好.
考虑:
#include <Rcpp.h>
using namespace Rcpp ;
// [[Rcpp::export]]
NumericVector exp2(NumericVector x) {
NumericVector z = Rcpp::clone(x);
int n = z.size();
for (int i=0; i<n; ++i)
z[i] = exp(z[i]);
return z;
}
// [[Rcpp::export]]
NumericVector expSugar(NumericVector x) {
return exp(x) ;
}
/*** R
library(microbenchmark)
x <- rcauchy(1000000)
microbenchmark(exp(x), exp2(x), expSugar(x))
*/
Run Code Online (Sandbox Code Playgroud)
随着Rcpp我得到:
$ RcppScript /tmp/exp.cpp
> library(microbenchmark)
> x <- rcauchy(1e+06)
> microbenchmark(exp(x), exp2(x), expSugar(x))
Unit: milliseconds
expr min lq median uq max neval
exp(x) 7.027006 7.222141 7.421041 8.631589 21.78305 100
exp2(x) 6.631870 6.790418 7.064199 8.145561 31.68552 100
expSugar(x) 6.491868 6.761909 6.888111 8.154433 27.36302 100
Run Code Online (Sandbox Code Playgroud)
如此好,但有些轶事的改进,可以通过各种内联等解释......如其他答案和评论中所述.
有了Rcpp11自动螺纹糖,我得到:
$ Rcpp11Script /tmp/exp.cpp
> library(microbenchmark)
> x <- rcauchy(1e+06)
> microbenchmark(exp(x), exp2(x), expSugar(x))
Unit: milliseconds
expr min lq median uq max neval
exp(x) 7.029882 7.077804 7.336214 7.656472 15.38953 100
exp2(x) 6.636234 6.748058 6.917803 7.017314 12.09187 100
expSugar(x) 1.652322 1.780998 1.962946 2.261093 12.91682 100
Run Code Online (Sandbox Code Playgroud)