Fibonacci numbers (Ruby)

From LiteratePrograms

Jump to: navigation, search
Other implementations: ALGOL 68 | Alice ML | bc | C | C Plus Plus templates | dc | E | Eiffel | Erlang | Forth | Haskell | Hume | Icon | Java | JavaScript | Lisp | Logo | Lua | Mercury | OCaml | occam | Oz | Pascal | PIR | PostScript | Python | Ruby | Scala | Scheme | Sed | sh | sh, iterative | T-SQL | Visual Basic .NET

The Fibonacci numbers are the integer sequence 0, 1, 1, 2, 3, 5, 8, 13, 21, ..., in which each item is formed by adding the previous two. The sequence can be defined recursively by

F(n) =  \begin{cases}    0             & n = 0 \\    1             & n = 1 \\    F(n-1)+F(n-2) & n > 1 \\   \end{cases} .

Fibonacci number programs that implement this definition directly are often used as introductory examples of recursion. However, many other algorithms for calculating (or making use of) Fibonacci numbers also exist.


Contents

Recursion

This simple ruby program uses recursion to print the first 10 Fibonacci numbers to the console.

<<Fibonacci.rb>>=
def fib(n)
  return n if (0..1).include? n
  fib(n-1) + fib(n-2)
end
test main

Iteration

Although it is based directly on the definition of a Fibonacci number, the recursive Fibonacci algorithm is extremely expensive, requiring time O(2n). It also performs a huge amount of redundant work because it computes many Fibonnaci values from scratch many times. A simple linear-time iterative approach which calculates each value of fib successively can avoid these issues:

<<FibonacciIterative.rb>>=
def fib(n)
	curr = 0
	succ = 1

	n.times do |i|
		curr, succ = succ, curr + succ
	end

	return curr
end
test main

There is another method, far shorter from [1]. It is probably the shortest you will find at only 35 charachters:

<<FibonacciIterative2.rb>>=
def fib(n)
p=proc{|x|x<3?1:p[x-1]+p[x-2]};p[n]
end
test main

Matrix Method

While the iterative method does run in O(n) time we can still improve on this by understanding the following formula:

\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^n =        \begin{pmatrix} F_{n+1} & F_n \\                        F_n     & F_{n-1} \end{pmatrix}.

From this we can create a simple O(lg(n)) time algorithm.

<<FibonacciMatrix.rb>>=
require 'matrix'

FIB_MATRIX = Matrix[[1,1],[1,0]]
def fib(n)
	(FIB_MATRIX**(n-1))[0,0]
end
test main

Testing

We can test all of the above implementations using a simple loop:

<<test main>>=
10.times do |i|
	puts fib(i)
end
Download code
Personal tools