--- title: "Fibonacci Numbers" author: "John Fox" output: html_document --- #### `r as.character(Sys.Date())` ```{r echo=FALSE} # include this code chunk as-is to set options knitr::opts_chunk$set(comment=NA, prompt=TRUE, fig.height=8, fig.width=8) # use fig.height=6.5, fig.width=6.5 for word output ``` Calculating Fibonacci Numbers by Recursion ------------------------------ ```{r} fib0 <- function(n, verbose=FALSE){ if (verbose) cat("n = ", n, " ") if (n <= 2) return(1) fib0(n - 1, verbose=verbose) + fib0(n - 2, verbose=verbose) } sapply(1:10, fib0) ``` I've included a verbose argument to trace the recursive function calls (see below). Calculating Fibonacci Numbers by Iteration --------------------------------------- ```{r} fib1 <- function(n){ if (n <= 2) return(1) last.minus.1 <- 1 last.minus.2 <- 1 for (i in 3:n){ save <- last.minus.1 last.minus.1 <- last.minus.1 + last.minus.2 last.minus.2 <- save } last.minus.1 } sapply(1:10, fib1) ``` Computing Fibonacci Numbers by Binet's Formula ------------------------ ```{r} fib2 <- function(n){ round(((1 + sqrt(5))/2)^n/sqrt(5)) } sapply(1:10, fib2) ``` Comparing the Efficiency of the three Solutions -------------------------- ```{r} options(scipen=10) # suppress scientific notation system.time(print(fib0(30))) system.time(print(fib1(70))) system.time(print(fib2(70))) ``` The latter two solutions are too fast to time with `system.time()` but we can get timings with the **microbenchmark** package: ```{r} library(microbenchmark) # need to install the microbenchmark package microbenchmark(fib1(70)) microbenchmark(fib2(70)) ``` As expected `fib2()`, which uses Binet's formula is much faster (proportionally) than `fib1()`, which uses iteration. `fib2(70)` produces the right answer, but not `fib2(72)`: ```{r} fib1(71) fib2(71) ``` To see why the recursive function `fib0()` is so inefficient, trace the computation: ```{r} fib0(8, verbose=TRUE) ``` It's apparent that some of the same Fibonacci numbers (e.g., for n = 2) end up being computed over and over and over again.