教育 - 使用 Rcpp 了解递归函数的可变性能

Educational - understanding variable performance of recursive functions with Rcpp

这个问题不是实际问题,我只是在寻找对观察到的事件的合理解释。我正在阅读 Dirk Eddelbuettel 的 Seamless R and C++ Integration with Rcpp (Use R!)。在介绍之后,我正在看两个简单的 "Fibonacci functions".

在RStudio中我有一个结构如下的cpp文件

fib_fun.cpp

#include <Rcpp.h>

// [[Rcpp::export]]
int fibonacci(const int x) {
    if (x < 2)
        return x;
    else
        return (fibonacci(x -1)) + fibonacci(x-2);
}

/*** R
# Call the fib function defined in R
fibonacci(10)
*/

我也有相同功能的内联实现:

inline_fib.R

# Inline fib implementation
incltxt <- "int fibonacci(const int x) {
            if (x == 0) return(0);
            if (x == 1) return(1);
            return fibonacci(x - 1) + fibonacci(x - 2);
            }"

# Inline call
require(inline)
fibRcpp <- cxxfunction(signature(xs = "int"), plugin = "Rcpp",
                       includes = incltxt,
                       body = "int x = Rcpp::as<int>(xs);
                               return Rcpp::wrap(fibonacci(x));")

当我对函数进行基准测试时,我得到以下结果:

> microbenchmark(fibonacci(10), fibRcpp(10), times = 10)
Unit: microseconds
          expr   min    lq   mean median    uq    max neval
 fibonacci(10) 3.121 3.198 5.5192  3.447 3.886 23.491    10
   fibRcpp(10) 1.176 1.398 3.9520  1.558 1.709 25.721    10

问题

  1. 我想了解为什么这两个函数在性能上有显着差异?
  2. 关于使用 Rcpp 的实用性,什么通常被认为是好的做法?出于天真,我的第一个直觉是编写一个函数并通过 sourceCpp 获取它,但这种解决方案似乎要慢得多。

基准代码

require(microbenchmark); require(Rcpp); require(inline)
sourceCpp("fib_fun.cpp"); source("inline_fib.R")
microbenchmark(fibonacci(10), fibRcpp(10), times = 10)

评论回复

我尝试使用 unsigned int 而不是 int 的函数,结果:

Unit: microseconds
          expr   min    lq   mean median    uq    max neval
 fibonacci(10) 2.908 2.992 5.0369  3.267 3.598 20.291    10
   fibRcpp(10) 1.201 1.263 6.3523  1.424 1.639 50.536    10

以上都是好评。

该函数 x=10 上太轻了,你需要比 times=10 更频繁地调用 ] 找到任何有意义的东西。您正在测量噪音。

至于样式,我们大多数人更喜欢 fibonacci() 通过 Rcpp 属性...