14

I'm trying to write a function in Workbench which will generate a Fibonacci sequence starting with F0 = 0 and F1 = 1. So far I have this written

fibonacciSequence[n_] := 
Module[{fPrev = 0, fNext = 1, i = 0}, 
While[i++ < n, {fPrev, fNext} = {fNext, fPrev + fNext}];
fNext]

How do I modify the function to make it print out a list like the one below when fibonacciSequence[15] is called?

{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}

Sorry, but I am very new to Mathematica and my professor didn't give us much instructions or examples of similar functions.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Adrian
  • 141
  • 1
  • 3
  • 1
    you may try Table[Fibonacci[n], {n, 15}] see the doc http://reference.wolfram.com/mathematica/ref/Fibonacci.html – s.s.o Sep 03 '13 at 14:38
  • 3
    @s.s.o I'd use Array[Fibonacci, 15] or Fibonacci @ Range @ 15 myself. – Mr.Wizard Sep 03 '13 at 14:47
  • 1
    @Mr.Wizard Anytime educative suggestions are welcome. Time to practice alternative coding :) Thank you. – s.s.o Sep 04 '13 at 06:49

10 Answers10

30

I'm really surprised if this question isn't a duplicate, but since I failed to find one that asked about the Fibonacci sequence rather than someone using it as an example, I'll answer.

The most natural approach, besides using the built-in Fibonacci function, recursion:

f[0] = 0; f[1] = 1;
f[n_] := f[n] = f[n - 1] + f[n - 2]  (* note memoization *)

Array[f, 10]
{1, 1, 2, 3, 5, 8, 13, 21, 34, 55}

Better performing may be Nest and NestList:

fibonacciList[n_] := Module[{x = 0}, NestList[x + (x = #) &, 1, n - 1]]

fibonacciList[10]
{1, 1, 2, 3, 5, 8, 13, 21, 34, 55}

Another useful way uses LinearRecurrence:

LinearRecurrence[{1, 1}, {1, 1}, 10]
{1, 1, 2, 3, 5, 8, 13, 21, 34, 55}

Hopefully these examples inspire you.


I now note that you request the sequence starting from zero. Most of these are easy to adapt or modify. The first one is simply:

Array[f, 10, 0]
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}

For the second you may instead write:

fibonacciList2[n_] := Module[{x = 1}, NestList[x + (x = #) &, 0, n - 1]]

fibonacciList2[10]
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}

The last one merely needs the proper seed:

LinearRecurrence[{1, 1}, {0, 1}, 10]
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}

Finally, taking the question at face value you can modify your code to return fPrev rather than fNext to start from zero:

fibonacciSequence[n_] := 
 Module[{fPrev = 0, fNext = 1, i = 0}, 
  While[i++ < n, {fPrev, fNext} = {fNext, fPrev + fNext}];
  fPrev
 ]

Array[fibonacciSequence, 10, 0]
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}

Addendum for rcollyer:

$fibList = {0, 1};
    fibonacciList[n_] /; n <= Length@$fibList := Take[$fibList, n]
    fibonacciList[n_] := $fibList =
  $fibList ~Join~ 
       Module[{x = $fibList[[-2]]}, 
        Rest@NestList[x + (x = #) &, $fibList[[-1]], n - Length@$fibList]]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 2
    For bonus points, memoize fibonacciList without harming initial performance. :D – rcollyer Sep 03 '13 at 14:52
  • @rcollyer Interesting challenge. Do you have a solution? – Mr.Wizard Sep 03 '13 at 14:56
  • Actually, I don't. I just wanted to poke the bear and see what came of it. I'll have to think on it. Oh, and +1, as already given. – rcollyer Sep 03 '13 at 14:59
  • 1
    @rcollyer I gave it a shot. – Mr.Wizard Sep 03 '13 at 15:28
  • Interestingly enough, on my machine, fibList[50000] takes 0.04s less time on first pass than fibList2[50000] does. The second time is no contest. So, performance is the same/slightly better on initial pass. Do Not attempt fibList2[500000]; I had to kill my kernel as it ate up all remaining mem on my machine. (Where fibList -> fibonacciList.) Additionally, fibList[50000] was still approx. 0.1 s. So, unless a large number of fib nums need to be calculated, I can't see where even memoization is all that useful here. – rcollyer Sep 03 '13 at 15:47
  • (cont'd) curiously enough, I'd like to try it with the last two identities found in this section of wikipedia. I think they would be more memory efficient than the plain recursive form, and possibly faster as there are fewer calcs. Yet, again, there is likely little advantage in doing so, other than saying you did it. :P – rcollyer Sep 03 '13 at 15:50
  • @rcollyer Which identities? Are you thinking of something like Round[(GoldenRatio^(2 #) - (-1)^#)/(Sqrt[5] GoldenRatio^#)] &? – Mr.Wizard Sep 03 '13 at 15:53
  • That's certainly doable, but I was thinking $$F_{2n-1} = F^2_n + F^2_{n - 1}$$ $$F_{2n} = (2 F_{n - 1} + F_n) F_n$$ or possibly one of the other identities. But, the other ones are much more involved in implementation. – rcollyer Sep 03 '13 at 16:09
  • Recursion, like you used in your first solution, may look like the most natural solution, but in practice its performance is just horrible. This is easy to see, as calculating f[n-1] implies calculating f[n-2], which you do again later on. Computing f[50] takes over 12 billion additions, compared to 50 when calculating iteratively. Fibonacci numbers are probably the best example where a perfect recursive definition is not a good idea to implement. – stevenvh Jul 28 '15 at 08:47
  • @stevenvh I am somewhat puzzled by your comment. Memoization, as implemented in this answer, largely takes care of that problem. That's kind of the point? Of course direct iteration is better which is why I provided that solution as well. – Mr.Wizard Jul 28 '15 at 15:23
15

This is probably defeating your professor's unspoken desire, but no one explicitly said you required a recursion. It may or may not entertain you to know Binet's formula. Without checking, I would guess that this approach is similar to how the built in function computes Fibonacci numbers. It is clearly computationally cheaper than any sort of recursion or nesting, and that would be noticeable deep into the sequence. This is a bit slower than the built in function, but it will do say the 3 millionth number pretty fast:

fibos[n_] := RootReduce@(((1 + Sqrt[5])/2)^n - ((1 - Sqrt[5])/2)^n)/Sqrt[5]

This could be made much shorter with some small modicum of effort. To get your table, implement it with something like:

Table[fibos[i], {i, 0, 15}]
J. W. Perry
  • 1,080
  • 1
  • 6
  • 11
12
f[n_]:=Union @@ NestList[{{0,1},{1,1}}.# &, {1, 1}, n]

EDIT

fib[n_]:=NestList[{{0,1},{1,1}}.# &, {0, 1}, n][[All,1]]

and MatrixPower method:

fn[n_]:=First[MatrixPower[{{1,1},{1,0},n-1].{1,0}]
ubpdqn
  • 60,617
  • 3
  • 59
  • 148
11

In Mathematica 10.2 one can use the new function SequenceFoldList:

fib[n_] := SequenceFoldList[Plus, {0, 1}, ConstantArray[0, n - 1]];
fib[15]

{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}

Use SequenceFold to obtain just the last element.

RunnyKine
  • 33,088
  • 3
  • 109
  • 176
10

Also taking your question at face value, but making the fix faster:

fibonacciSequence2[n_] := Module[
  {fPrev = 0, fNext = 1, i = 0, list = {0}},
  While[i++ < n,
   {fPrev, fNext} = {fNext, fPrev + fNext};
   list = {fPrev, list}
   ];
  Reverse@Flatten[list]
  ]

 fibonacciSequence2[5000] // Timing

This way of constructing a list has a name, it's called linked lists.

When I compare this with Mr. Wizard's fix for the 5000 first values, I get 0.015053 seconds instead of 21.764429. (Mr.Wizard did not intend speed and I get that. His other solutions are even faster than this, I checked the last one and it took just 0.008132.)

(Also this prints the list as requested)

C. E.
  • 70,533
  • 6
  • 140
  • 264
9

This may do what you want:

Clear["`*"];
fibonacciSequence[n_] :=
 Module[{fPrev = 1, fNext = 0},
  Table[{fPrev, fNext} = {fNext, fPrev + fNext}, {n + 1}][[;; , 1]]
  ]

fibonacciSequence[15]
(* {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610} *)

a = 1; b = 0; Table[b = a + (a = b), {10}]
NestList[{+##, #} & @@ # &, {1, 1}, 10][[;; , 1]]
Nest[#~Append~Tr@#[[-2 ;;]] &, {1, 1}, 10]
Nest[# /. {a___, x_, y_} -> {a, x, y, x + y} &, {1, 1}, 10]
Nest[{1, 1}~Join~(Most@# + Rest@#) &, {1, 1}, 10]
Nest[Accumulate[{1, 0}~Join~#] &, {}, 5]
chyanog
  • 15,542
  • 3
  • 40
  • 78
4

Tail recursive Fibonacci sequence generator

fiboSequence[n_, a_, b_] := fiboSequence[n - 1, b, Sow[a] + b]
fiboSequence[0, a_, b_] := Sow[a]
fiboSequence[n_] := Reap[fiboSequence[n, 0, 1]][[2, 1]]

fiboSequence[15]

$\ ${0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}

Pattern matching Fibonacci sequence generator

fiboSequence2[n_] := 
 Quiet@ReplaceRepeated[{0, 1}, {x___, a_, b_} :> {x, a, b, a + b}, MaxIterations -> n - 1]

fiboSequence2[15]

$\ ${0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}

Karsten7
  • 27,448
  • 5
  • 73
  • 134
3

For diversity reasons:

Table[a[i] /. 
  RSolve[{a[n] == a[n - 1] + a[n - 2], a[1] == 1, a[2] == 1}, a, n][[1]], 
  {i, 0, 15}]

{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}

or as @J.M. ironically remarked:

Array[DifferenceRoot[
  Function[{a, n}, {a[n] == a[n - 1] + a[n - 2], a[1] == 1, a[2] == 1}]], 16, 0]
garej
  • 4,865
  • 2
  • 19
  • 42
3

For giggles, here is a contour integral method (based on Cauchy's formula) for computing the Fibonacci numbers:

Table[Round[Re[NIntegrate[1/((1 - z - z^2) z^n),
                          {z, 1/2, I/2, -1/2, -I/2, 1/2}]/(2 π I)]],
      {n, 10}]
   {1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
2

Another natural approach is to use the built-in RecurrenceTable

RecurrenceTable[{f[n] == f[n - 1] + f[n - 2], f[1] == 1, 
  f[0] == 0}, f, {n, 0, 15}]
(* {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610} *)
Jason B.
  • 68,381
  • 3
  • 139
  • 286