再帰でも速い

fibR <- function(seq) {
    if (seq == 0) return(0);
    if (seq == 1) return(1);
    return (fibR(seq - 1) + fibR(seq - 2));
}
    • 再帰しているから、べたに、値を「格納しながら進む」ことになる。ソースは簡単だけれど、処理はまだるっこしい
  • Rcppを使うと
library(Rcpp)
library(inline)
incltxt <- '
int fibonacci(const int x) {
   if (x == 0) return(0);
   if (x == 1) return(1);
   return (fibonacci(x - 1)) + fibonacci(x - 2);
}'

## now use the snipped above as well as one argument conversion
## in as well as out to provide Fibonacci numbers via C++
fibRcpp <- cxxfunction(signature(xs="int"),
                       plugin="Rcpp",
                       incl=incltxt,
                       body='
   int x = Rcpp::as<int>(xs);
   return Rcpp::wrap( fibonacci(x) );
')
  • Rのコードをコンパイルするという仕組みもあって、それはcompilerパッケージがやるらしいのだが、それもやってみる
library(compiler)
fibRC <- cmpfun(fibR)
  • 速さを比較する
N <- 25
res <- benchmark(fibR(N),
                 fibRC(N),
                 fibRcpp(N),
                 columns=c("test", "replications", "elapsed",
                           "relative", "user.self", "sys.self"),
                 order="relative",
                 replications=1)
print(res)  ## show result
  • Rcppはほとんど時間がかからないのに、RとRのコンパイルだけの処理、では、時間がかかりますよ、と。(例にあるとおりに、N=35にしたりすると、すごい時間がかかってしまう)
# N <- 28の例
> print(res)  ## show result
        test replications elapsed relative user.self sys.self
1    fibR(N)            1    9.88       NA      9.60     0.03
2   fibRC(N)            1    8.78       NA      8.61     0.00
3 fibRcpp(N)            1    0.00       NA      0.00     0.00
> print(res)  ## show result
        test replications elapsed relative user.self sys.self
1    fibR(N)            1    2.03       NA      2.03        0
2   fibRC(N)            1    2.04       NA      2.01        0
3 fibRcpp(N)            1    0.00       NA      0.00        0