The definition of fibonaci(n) is:
fibonacci (n) = fibonacci (n-1) + fibonacci (n-2)
The naive implementation in Haskell
fibonacci :: Integer -> Integer
fibonacci 0 = 1
fibonacci 1 = 1
fibonacci x = fibonacci (x-1) + fibonacci (x-2)
All formulas can be traced back to this definition, some which run very quickly, some of which run very slowly. The implementation above has O(n) = 2^n
In the spirit of your question, let me remove the use of lists and give you something that runs in O(n) I.e. let's not hold all the fibonaccis from 0 to n in a list.
If we have a triple (a tuple with three members) that looks like:
(n, fibonacci[n-1], fibonacci[n])
Remembering the initial definition, we can calculate the next triple from the last triple:
(n+1, fibonacci[n], fibonacci[n-1] + fibonacci[n])
= (n+1, fibonacci[n], fibonacci[n+1])
And the next triple from the last triple:
(n+2, fibonacci[n+1], fibonacci[n] + fibonacci[n+1])
= (n+1, fibonacci[n+1], fibonacci[n+2])
And so on...
n = 0 => (0,0,1)
n = 1 => (1,1,1) - calculated from the previous triple
n = 2 => (2,1,2) - calculated from the previous triple
n = 3 => (3,2,3) - calculated from the previous triple
n = 4 => (4,3,5) - calculated from the previous triple
n = 5 => (5,5,8) - calculated from the previous triple
Let's implement this in Haskell and use self explanatory variable names:
nextTripleIfCurrentNIsLessThanN :: (Int, Integer, Integer) -> Int -> (Int, Integer, Integer)
nextTripleIfCurrentNIsLessThanN (currentN, x, y) n = if currentN < n
then nextTripleIfCurrentNIsLessThanN (currentN + 1, y, x + y) n
else (currentN, x, y)
thirdElementOfTriple :: (x,y,z) -> z
thirdElementOfTriple (x,y,z) = z
fibonacci :: Int -> Integer
fibonacci n = thirdElementOfTriple (nextTripleIfCurrentNIsLessThanN (0,0,1) n)
This will work in O(n) [It is mildly quadratic which shows up in large numbers. The reason for that is that adding big numbers is more costly than adding small ones. But that's a separate discussion about model of computation.]
fibonacci 0
1
fibonacci 1
1
fibonacci 2
2
fibonacci 3
3
fibonacci 4
5
fibonacci 5
8
fibonacci 5000
6276302800488957086035253108349684055478528702736457439025824448927937256811663264475883711527806250329984690249846819800648580083040107584710332687596562185073640422286799239932615797105974710857095487342820351307477141875012176874307156016229965832589137779724973854362777629878229505500260477136108363709090010421536915488632339240756987974122598603591920306874926755600361865354330444681915154695741851960071089944015319300128574107662757054790648152751366475529121877212785489665101733755898580317984402963873738187000120737824193162011399200547424034440836239726275765901190914513013217132050988064832024783370583789324109052449717186857327239783000020791777804503930439875068662687670678802914269784817022567088069496231111407908953313902398529655056082228598715882365779469902465675715699187225655878240668599547496218159297881601061923195562143932693324644219266564617042934227893371179832389642895285401263875342640468017378925921483580111278055044254198382265567395946431803304304326865077742925818757370691726168228648841319231470626
fibSerie a b = a : (fibSerie b (a+b))
and then:fibs = fibSerie 1 1
. – jpmarinierω = 2 + min ω (ω - 1)
.zipWith
produces an (infinite) list of integers here, not just one integer, so it's not2 + 1
overall elements, but2 + ω
. which isω
. – Will Ness