Fibonacci numbers (Oz)

From LiteratePrograms

Jump to: navigation, search
Other implementations: ALGOL 68 | Alice ML | bc | C | C Plus Plus templates | dc | E | Eiffel | Erlang | Forth | FORTRAN | Haskell | Hume | Icon | Java | JavaScript | Lisp | Logo | Lua | Mercury | OCaml | occam | Oz | Pascal | PIR | PostScript | Python | Ruby | Scala | Scheme | Sed | sh | sh, iterative | Smalltalk | 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

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

Implementation

We describe several different implementations for calculating the fibonacci numbers in Oz:

<<Fib.oz>>=
functor
import
   System
   Application
define
   recursive fib
   memoized fib
   iterative fib
   testdriver
end

Recursive

Here is a very simple recursive implementation. This will become slow on big numbers, because the numbers are recalculated for each recursion.

<<recursive fib>>=
fun {RecursiveFib N}
   if N < 2 then N else {RecursiveFib N - 1} + {RecursiveFib N - 2} end
end

Memoized recursion

Although the recursive implementation given above is elegant and close to the mathematical definition, it is not very practical. Calculating the nth fibonacci number requires calculating two smaller fibonacci numbers, which in turn require two additional recursive calls each, and so on until all branches reach 1. As a consequence, the time required to calculate the fibonacci numbers is exponential in n (it is about Φn, where Φ is the golden ratio). To remedy this, we can employ memoization to cache previous computations:

<<memoized fib>>=
Memo = {NewDictionary}
fun {MemoizedFib N}
   if {Dictionary.member Memo N}
   then {Dictionary.get Memo N}
   else
      FibN
   in
      if N < 2 then FibN = N else FibN = {MemoizedFib N - 1} + {MemoizedFib N - 2} end
      {Dictionary.put Memo N FibN}
      FibN
   end
end

This memoized recursive implementation makes use of Oz's mutable Dictionary datatype to store and retrieve previously computed values.

Iteration

Another alternative for fast computation of fibonacci numbers is a simple linear-time iterative approach which calculates each fibonacci number successively. Although Oz supports mutable variables and for-loops, we have chosen here to implement a compact iterative routine that performs a tail-recursive, accumulative calculation:

<<iterative fib>>=
fun {IterativeFib N}
   fun {Fib N F1 F2}
     if N < 1 then F1 else {Fib (N - 1) F2 (F1 + F2)} end
   end
in
   {Fib N 0 1}
end

Test driver

The test driver procedure runFib computes and prints the fibonacci numbers from n = 0 up to n = 30.

<<testdriver>>=
proc {RunFib F}
   for X in 0..30 do
      {System.showInfo "{" # {System.printName F} # " " # X # "} = " # {F X}}
   end
end

We apply RunFib to each of the implementations described above, and then exit.

<<testdriver>>=
{RunFib RecursiveFib}
{RunFib MemoizedFib}
{RunFib IterativeFib}
{Application.exit 0}
Download code
Views