好的,我知道答案,但受到this question的启发,我想对以下内容有一些很好的看法:为什么下面的Rcpp练习是ca.比内置exp()
快15%(对于长向量)?我们都知道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
答案 0 :(得分:8)
Base R倾向于对NA
进行更多检查,因此我们可以通过不做那样来赢得一点。另请注意,通过像循环展开这样的技巧(如在Rcpp Sugar中所做的那样),我们可以做得更好。
所以我添加了
Rcpp::cppFunction("NumericVector expSugar(NumericVector x) { return exp(x); }")
并且我得到了进一步的收益 - 用户端的代码更少:
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>
答案 1 :(得分:5)
如果您确实希望获得性能改进,则必须编写代码以利用底层硬件并发性。您可以使用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))
*/
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
如此好,但有点轶事改进,可以通过各种内联等解释......如其他答案和评论中所述。
使用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