8

OK、私は答えを知っていますが、この質問に触発されて、次の点について良い意見を求めたいと思います。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
4

2 に答える 2

8

ベース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 に答える