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

Educational - understanding variable performance of recursive functions with Rcpp

本文关键字:性能 递归函数 Rcpp 教育      更新时间:2023-10-16

这个问题不是实际问题,我只是想对观察到的现象做出合理的解释。我正在阅读Dirk Eddelbuettel的无缝R和C++与Rcpp集成(使用R!)。在介绍之后,我将研究两个简单的"斐波那契函数"。

在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更频繁地调用way才能找到任何有意义的东西。你在测量噪音。

至于风格,我们大多数人更喜欢fibonacci()通过Rcpp属性。。。