8

好的,我知道答案,但是受到这个问题的启发,我想就以下问题获得一些不错的意见:为什么下面的 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
4

2 回答 2

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> 
于 2014-10-17T18:55:32.917 回答
6

如果您真的想获得性能改进,则必须编写代码以利用底层硬件并发性。你可以使用这个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
于 2014-10-21T19:36:49.980 回答