Writing C++ in R with Rcpp

Author

Marie-Hélène Burle

Sometimes, parallelization is not an option, either because the code is hard to parallelize or because of lack of hardware. In such cases, one way to increase speed is to replace slow R code with C++. The package Rcpp makes this particularly easy by creating mappings between both languages.

Back to Fibonacci

Do you remember the Fibonacci numbers? Here was a naive implementation in R:

fib <- function(n) {
  if(n == 0) return(0)
  if(n == 1) return(1)
  Recall(n - 1) + Recall(n - 2)
}

This function gives the nth number in the sequence.

Example:

fib(30)
[1] 832040

Rcpp

Let’s translate this function in C++ within R!

First we need to load the Rcpp package:

library(Rcpp)

We then use the function cppFunction() to assign to an R function a function written in C++:

fibRcpp <- cppFunction( '
int fibonacci(const int x) {
   if (x == 0) return(0);
   if (x == 1) return(1);
   return (fibonacci(x - 1)) + fibonacci(x - 2);
}
' )

We can call our function as any R function:

fibRcpp(30)
[1] 832040

We can compare both functions:

library(bench)

n <- 30
mark(fib(n), fibRcpp(n))
# A tibble: 2 × 13
  expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
  <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>
1 fib(n)        1.66s    1.66s     0.601    44.7KB     22.8     1    38
2 fibRcpp(n)   1.08ms   1.08ms   901.       2.49KB      0     451     0
  total_time result    memory                 time            
    <bch:tm> <list>    <list>                 <list>          
1      1.66s <dbl [1]> <Rprofmem [6,778 × 3]> <bench_tm [1]>  
2   500.37ms <int [1]> <Rprofmem [1 × 3]>     <bench_tm [451]>
  gc                
  <list>            
1 <tibble [1 × 3]>  
2 <tibble [451 × 3]>
Warning message:
Some expressions had a GC in every iteration; so filtering is disabled.

The speedup is 1,537, which is amazing.

In this particular example, we saw that memoisation gives an even more incredible speedup (35,000!), but while memoisation will only work in very specific situations (e.g. recursive function calls), using C++ code is a general method to provide speedup. It is particularly useful when:

  • there are large numbers of function calls (R is particularly slow with function calls),
  • you need data structures that are missing in R,
  • you want to create efficient packages (fast R packages are written in C++ and many use Rcpp).

In this example, we declared the C++ function directly in R. It is possible to use source files instead.