Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This is a nice and simple example where <a href="http://dirk.eddelbuettel.com/code/rcpp.html" rel="noreferrer">Rcpp</a> can shine. </p> <p>So let us first recast functions 1 and 2 and their compiled counterparts:</p> <pre><code>library(inline) library(rbenchmark) library(compiler) fun1 &lt;- function(z) { for(i in 2:NROW(z)) { z[i] &lt;- ifelse(z[i-1]==1, 1, 0) } z } fun1c &lt;- cmpfun(fun1) fun2 &lt;- function(z) { for(i in 2:NROW(z)) { z[i] &lt;- if(z[i-1]==1) 1 else 0 } z } fun2c &lt;- cmpfun(fun2) </code></pre> <p>We write a <a href="http://dirk.eddelbuettel.com/code/rcpp.html" rel="noreferrer">Rcpp</a> variant very easily:</p> <pre><code>funRcpp &lt;- cxxfunction(signature(zs="numeric"), plugin="Rcpp", body=" Rcpp::NumericVector z = Rcpp::NumericVector(zs); int n = z.size(); for (int i=1; i&lt;n; i++) { z[i] = (z[i-1]==1.0 ? 1.0 : 0.0); } return(z); ") </code></pre> <p>This uses the <a href="http://cran.r-project.org/package=inline" rel="noreferrer">inline</a> package to compile, load and link the five-liner on the fly. </p> <p>Now we can define our test-date, which we make a little longer than the original (as just running the original too few times result in unmeasurable times):</p> <pre><code>R&gt; z &lt;- rep(c(1,1,0,0,0,0), 100) R&gt; identical(fun1(z),fun2(z),fun1c(z),fun2c(z),funRcpp(z)) [1] TRUE R&gt; </code></pre> <p>All answers are seen as identical. </p> <p>Finally, we can benchmark:</p> <pre><code>R&gt; res &lt;- benchmark(fun1(z), fun2(z), + fun1c(z), fun2c(z), + funRcpp(z), + columns=c("test", "replications", "elapsed", + "relative", "user.self", "sys.self"), + order="relative", + replications=1000) R&gt; print(res) test replications elapsed relative user.self sys.self 5 funRcpp(z) 1000 0.005 1.0 0.01 0 4 fun2c(z) 1000 0.466 93.2 0.46 0 2 fun2(z) 1000 1.918 383.6 1.92 0 3 fun1c(z) 1000 10.865 2173.0 10.86 0 1 fun1(z) 1000 12.480 2496.0 12.47 0 </code></pre> <p>The compiled version wins by a factor of almost 400 against the best R version, and almost 100 against its byte-compiled variant. For function 1, the byte compilation matters much less and both variants trail the C++ by a factor of <em>well over two-thousand</em>.</p> <p>It took about one minute to write the C++ version. The speed gain suggests it was a minute well spent.</p> <p>For comparison, here is the result for the original short vector called more often:</p> <pre><code>R&gt; z &lt;- c(1,1,0,0,0,0) R&gt; res2 &lt;- benchmark(fun1(z), fun2(z), + fun1c(z), fun2c(z), + funRcpp(z), + columns=c("test", "replications", + "elapsed", "relative", "user.self", "sys.self"), + order="relative", + replications=10000) R&gt; print(res2) test replications elapsed relative user.self sys.self 5 funRcpp(z) 10000 0.046 1.000000 0.04 0 4 fun2c(z) 10000 0.132 2.869565 0.13 0 2 fun2(z) 10000 0.271 5.891304 0.27 0 3 fun1c(z) 10000 1.045 22.717391 1.05 0 1 fun1(z) 10000 1.202 26.130435 1.20 0 </code></pre> <p>The qualitative ranking is unchanged: the <a href="http://dirk.eddelbuettel.com/code/rcpp.html" rel="noreferrer">Rcpp</a> version dominates, function2 is second-best. with the byte-compiled version being about twice as fast that the plain R variant, but still almost three times slower than the C++ version. And the relative difference are lower: relatively speaking, the function call overhead matters less and the actual looping matters more: C++ gets a bigger advantage on the actual loop operations in the longer vectors. That it is an important result as it suggests that more real-life sized data, the compiled version may reap a larger benefit.</p> <p><em>Edited to correct two small oversights in the code examples. And edited again with thanks to Josh to catch a setup error relative to fun2c.</em></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload