14

I am a CSE student and preparing myself for programming contest.Now I am working on Fibonacci series. I have a input file of size about some Kilo bytes containing positive integers. Input formate looks like

3 5 6 7 8 0

A zero means the end of file. Output should like

2 
5 
8 
13 
21 

my code is

#include<stdio.h>

int fibonacci(int n) {
  if (n==1 || n==2)
    return 1;
  else
    return fibonacci(n-1) +fibonacci(n-2);
}
int main() {
  int z;
  FILE * fp;    
  fp = fopen ("input.txt","r");    
  while(fscanf(fp,"%d", &z) && z) 
   printf("%d \n",fibonacci(z));
  return 0;
}

The code works fine for sample input and provide accurate result but problem is for my real input set it is taking more time than my time limit. Can anyone help me out.

Mehedi
  • 141
  • 1
  • 1
  • 6

22 Answers22

20

You could simply use a tail recursion version of a function that returns the two last fibonacci numbers if you have a limit on the memory.

int fib(int n)
{
    int a = 0;
    int b = 1;
    while (n-- > 1) {
        int t = a;
        a = b;
        b += t;
    }
    return b;
}

This is O(n) and needs a constant space.

Kru
  • 4,195
  • 24
  • 31
  • +1 for simplicity. This also scales very nicely to a trivial bigint implementation where `a` and `b` are arrays... you could even make them base-1000000000 bigints so it's easy to print the results once you're done. – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:25
  • 1
    Just to add my 2 cents, this is a bottom-up approach using the memoization technique others have mentioned already. This technique is a dynamic programming technique: http://en.wikipedia.org/wiki/Dynamic_programming – Pin Jul 27 '10 at 10:49
  • Just for those who start the sequence as (0, 1, 1, 2, 3, 5...) you can set a = 1, b = 0, and the while loop as (n-- > 1). Thank you for this awesome code Kru!!! – Charis Moutafidis Jun 12 '18 at 20:02
  • Wouldn't it be better to see if `n-- >= 2`? And use long instead of int? – Flimtix Oct 25 '21 at 13:53
14

You should probably look into memoization.

http://en.wikipedia.org/wiki/Memoization

It has an explanation and a fib example right there

Xzhsh
  • 2,239
  • 2
  • 22
  • 32
  • 1
    It's also irrelevant since the number of Fibonacci numbers which fit in `int` is so small you can just "memoize" them at compile time in much less space than the code to compute them. – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:18
  • 2
    @R - But it's better that the OP learn this technique, because it's very valuable. So I wouldn't say it's irrelevant at all, and it's especially important in programming contests. It's good to learn the technique on a simpler problem, like fibonacci, then it can be applied to more difficult problems. Also, 64-bit integers could be used, and then larger answers could be stored. Or in C# 4.0 or JAVA, there's also BigInteger, so extremely large numbers could even be stored. – dcp Jul 27 '10 at 09:05
13

You can do this by matrix multiplictation, raising the matrix to power n and then multiply it by an vector. You can raise it to power in logaritmic time.

I think you can find the problem here. It's in romanian but you can translate it with google translate. It's exactly what you want, and the solution it's listed there.

Teodor Pripoae
  • 1,388
  • 1
  • 11
  • 26
  • I think you are responding to a different question. This isn't even remotely related to fibonacci numbers. – A. Levy Jul 26 '10 at 18:07
  • 4
    @A. Levy - yes, it is related, you can raise a certain matrix to a certain power and get fibonacci numbers in `O(log n)`. I agree that the answer is pretty vague about it however, and that the link is pretty useless, as knowing matrix multiplication won't really help you see the solution. Maybe he meant to link to the fibonacci page. Either way, the answer isn't wrong, so personally I don't see the need for downvoting. – IVlad Jul 26 '10 at 18:12
  • 5
    It is quite related to fibonacci numbers. For example, see algorithm 5 of: http://www.ics.uci.edu/~eppstein/161/960109.html This answer comes up pretty often here on stackoverflow each time a variation of this question gets asked (which is how I knew of it, the link is just the first hit of a google search) – McBeth Jul 26 '10 at 18:14
  • @A.Levy worked example here http://stackoverflow.com/questions/1525521/nth-fibonacci-number-in-sublinear-time/1526837#1526837 – Pete Kirkham Jul 26 '10 at 18:17
  • Here is a prove of what i said before, it's translated with google translate. http://translate.google.com/translate?js=y&prev=_t&hl=en&ie=UTF-8&layout=1&eotf=1&u=http://infoarena.ro/problema/kfib&sl=ro&tl=en – Teodor Pripoae Jul 26 '10 at 18:27
  • maybe the best solution in this situation – swegi Jul 26 '10 at 19:00
  • 1
    Huh, what do you know...I've never heard of that before. I retract my down vote and add an up vote. Thanks for teaching me something new Teodor! – A. Levy Jul 27 '10 at 05:31
  • When you have a linear recurence, you can always do it in o(log n * k^3), where k is the size of the matrix. If you need only a few of the last elements you can do it faster with matrix multiplication. – Teodor Pripoae Jul 27 '10 at 12:25
10

Your algorithm is recursive, and approximately has O(2^N) complexity.

This issue has been discussed on stackoverflow before: Computational complexity of Fibonacci Sequence

There is also a faster implementation posted in that particular discussion.

Community
  • 1
  • 1
sukru
  • 2,229
  • 14
  • 15
8

Look in Wikipedia, there is a formula that gives the number in the Fibonacci sequence with no recursion at all

rtruszk
  • 3,902
  • 13
  • 36
  • 53
David Brunelle
  • 6,528
  • 11
  • 64
  • 104
  • No recursion and no guarantee of exact results. – IVlad Jul 26 '10 at 18:15
  • 2
    Why no exact result ? This formula actually gives the exact answer, given you don't round up while calculatin. Grant the formula IS complicated, but it's execution time is also independant of the number you are looking for. – David Brunelle Jul 26 '10 at 18:17
  • @David Brunelle - no exact result because irrational numbers don't exist for a computer. There exist only rational approximations for those irrational numbers. – IVlad Jul 26 '10 at 18:19
  • 4
    @IVlad: That is irrelevant. So long as a formula is converging, rounding is safe once the convergence is close enough (and so long as you pay attention to significant digits, obviously). – Brian Jul 26 '10 at 18:22
  • All numbers can be approximated as accurate as needed, thus the formula is exact enough for all practical purposes (i.e. rounding to an integer at the end) even if applied on a computer. Of course, one shouldn't use IEEE floating point numbers. – swegi Jul 26 '10 at 18:24
  • @Brian - I'm not sure what you mean by a formula converging, the formula is not a series. I'm guessing you mean as long as you use enough digits in the golden ratio. Then you'll have to implement your own floating point datatype that can hold enough digits, you're going to need an algorithm that computes the golden ratio to a given number of digits, and you're going to need to know how many digits you need for the formula to give correct results. Do you think this to be worth the time or efficient? – IVlad Jul 26 '10 at 18:27
  • @IVlad : No, I mean that the formula becomes more accurate at higher values of N. If it did not converge, it would merely be an approximation, and would be useless. As is, it will work fine, if used carefully. This is a perfectly reasonable way to generate Fibonacci numbers if your goal is to generate arbitrary numbers rather than sequential numbers. In truth, I think the formula is actually exact when you apply it properly, but I'm rusty on this stuff. – Brian Jul 26 '10 at 18:32
  • @IVlad: You can just use the right tool for the job, i.e. mathematica or maple or whatever math system you like – swegi Jul 26 '10 at 18:32
  • @Brian - I wrote a quick program in g++ that uses the formula to calculate fib numbers. I'm noticing errors already at the 72nd fibonacci number. How would you implement it in C or C++ to give correct results at least until it overflows? I'm using this page for reference: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html Program coming in the next comment. @swegi - yes, but the question is about C, so what if I don't like any math system and I like C or C++? :) – IVlad Jul 26 '10 at 18:41
  • 1
    int main() { const double goldenRatio = (1.0 + sqrt(5.0)) / 2.0; for ( int i = 1; i <= 100; ++i ) { cout << "The " << i << "th fibonacci number is: "; cout << (long long)((pow(goldenRatio, (double)i) - pow(1 - goldenRatio, (double)i)) / sqrt(5.0)); cout << endl; } return 0; } Sorry for the way it looks. – IVlad Jul 26 '10 at 18:42
  • @Brian - I said C or C++. Are you really going to pick on that? :) The floating-point capabilities of the two are basically the same. – IVlad Jul 26 '10 at 18:44
  • @IVlad: At least maple has a C interface. – swegi Jul 26 '10 at 18:49
  • 1
    @swegi - I didn't know that, but my point is there are potential floating point errors that you have to deal with in some cases. They don't allow maple in programming contests for example. All I'm saying is that the formula is not always the best answer as it can easily produce wrong results. If you have access to certain tools, then great. It's also good from a theoretical standpoint, and if the OP is dealing with 32 bit numbers, then it might also be good for him. Again, my point is that it **can** cause errors in this situation. – IVlad Jul 26 '10 at 18:51
  • @IVlad: If you've been silly enough to use a double thinking every digit it displays is a digit of precision... Keep in mind that you lose a digit on every operation. Complaining about it not being able to handle math at the border of precision maximums is nitpicky; there is no surprise here. – Brian Jul 26 '10 at 18:59
  • @Brian - `long long` has 64 bits. There's no nitpicking on my part, I'm just saying the formula is not a good idea to use directly in a language such as C++ precisely BECAUSE doubles are unreliable! That's what I've been saying all along: that it won't be able to handle it! – IVlad Jul 26 '10 at 19:04
  • All of those problem comes from the fact that most language uses a structure for floating point that generate rounding error up to a certain point. Aren't there any object or data structure that, while not as efficient in term of space, could accomondate huge floating point number with no errors ? I mean, this isn't rocket science after all... – David Brunelle Jul 26 '10 at 19:09
  • @IVlad : Yes, but the power operations are on doubles, not `long long` s. – Brian Jul 26 '10 at 19:13
  • The original question used `int`, and I'm pretty sure `int` will overflow long before you hit the precision limits of `double`... – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:22
6

Use memoization. That is, you cache the answers to avoid unnecessary recursive calls.

Here's a code example:

#include <stdio.h>

int memo[10000]; // adjust to however big you need, but the result must fit in an int
                 // and keep in mind that fibonacci values grow rapidly :)

int fibonacci(int n) {
  if (memo[n] != -1)
    return memo[n];

  if (n==1 || n==2)
    return 1;
  else
    return memo[n] = fibonacci(n-1) +fibonacci(n-2);
}
int main() {
  for(int i = 0; i < 10000; ++i)
    memo[i] = -1;
  fibonacci(50);
}
dcp
  • 54,410
  • 22
  • 144
  • 164
  • I don't think calculating `fibonacci(500)` like this will work though :). – IVlad Jul 26 '10 at 17:57
  • Yes, it will overflow. I changed it to 50. Thanks for your comment :). – dcp Jul 26 '10 at 18:01
  • 1
    Now remove the useless code and replace it with `static const int memo[50] = { 0, 1, 1, 2, 3, 5, ... };` – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:23
  • 1
    @R- The point of the memo array is for the memoization, that is, we use that array to avoid unnecessary recursive calls. Pre-initializing the array with the answers defeats the purpose, we could just eliminate the fibonacci function completely. Maybe you need to read up on the memoization link I posted. – dcp Jul 27 '10 at 09:01
4

Nobody mentioned the 2 value stack array version, so I'll just do it for completeness.

// do not call with i == 0
uint64_t Fibonacci(uint64_t i)
{
  // we'll only use two values on stack,
  // initialized with F(1) and F(2)
  uint64_t a[2] = {1, 1};

  // We do not enter loop if initial i was 1 or 2 
  while (i-- > 2)
    // A bitwise AND allows switching the storing of the new value
    // from index 0 to index 1.
    a[i & 1] = a[0] + a[1];

    // since the last value of i was 0 (decrementing i),
    // the return value is always in a[0 & 1] => a[0].
  return a[0];
}                                                                

This is a O(n) constant stack space solution that will perform slightly the same than memoization when compiled with optimization.

// Calc of fibonacci f(99), gcc -O2
Benchmark            Time(ns)    CPU(ns) Iterations
BM_2stack/99                2          2  416666667
BM_memoization/99           2          2  318181818

The BM_memoization used here will initialize the array only once and reuse it for every other call.

The 2 value stack array version performs identically as a version with a temporary variable when optimized.

BlakBat
  • 1,835
  • 5
  • 17
  • 21
  • The question read `Can anyone help me [meet my time limit]?`. With a vanilla recursive code presented as too slow, please argue how your proposition is faster, or provide measurement mechanism & results. – greybeard Jun 16 '16 at 18:02
  • Added a benchmark against memoization when optimized. – BlakBat Jun 17 '16 at 11:14
  • While we are at it, you can even take this further by using pre-decrement (`--i`) instead of post-decrement ('i--') to reduce the execution by one more instruction. Right the line 'while (i-- > 2)' generates these instructions: `movl %eax, %ecx; addl $-1, %ecx`. If you change it to `while (--i > 1)` it will generate only `addl $-1, %eax`, removing one instruction. Super-minor detail but while we are at micro-optimization I wanted to mention this – MuhsinFatih Sep 04 '18 at 20:12
3

You can also use the fast doubling method of generating Fibonacci series Link: fastest-way-to-compute-fibonacci-number

It is actually derived from the results of the matrix exponentiation method.

0xh3xa
  • 4,801
  • 2
  • 14
  • 28
Neha
  • 41
  • 2
2

Use the golden-ratio

alt text

alt text

Community
  • 1
  • 1
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • 1
    This is a very bad idea if he needs exact results, which seems to be the case. – IVlad Jul 26 '10 at 18:14
  • Not necessarily, see the discussion on David Brunelle's post. – swegi Jul 26 '10 at 18:36
  • @IVlad - Yes, it will depend on the floating point representation, and on my 32 bit machine with a regular Float in Ruby, it starts to diverge around the 70th number. The precision has to be much higher and probably needs a hand written representation for larger numbers. – Anurag Jul 26 '10 at 18:53
  • Like @swegi and @Brian said, mathematical languages would offer that needed precision and be valid for much larger numbers, which will be an interesting test to conduct. – Anurag Jul 26 '10 at 18:56
  • @Anurag - true, it starts giving incorrect results at the 72nd number for me in C++, using doubles. Those numbers it gives incorrect results on wouldn't fit into 32 bit ints anyway, and I'm guessing the OP uses those. So I jumped the gun a litle on "very bad idea", I apologize. Still, errors are definitely something to look out for in such formulas. – IVlad Jul 26 '10 at 18:57
  • @Anurag, the question used `int` which overflows around the 50th Fibonacci number (for 32-bit int; much sooner for 16-bit `:)`) so 70 isn't so bad. – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:27
1

Matrix multiplication, no float arithmetic, O(log N) time complexity assuming integer multiplication/addition is done in constant time.

Here goes python code

def fib(n):
    x,y = 1,1
    mat = [1,1,1,0]
    n -= 1
    while n>0:
        if n&1==1:
            x,y = x*mat[0]+y*mat[1], x*mat[2]+y*mat[3]
        n >>= 1
        mat[0], mat[1], mat[2], mat[3] = mat[0]*mat[0]+mat[1]*mat[2], mat[0]*mat[1]+mat[1]*mat[3], mat[0]*mat[2]+mat[2]*mat[3], mat[1]*mat[2]+mat[3]*mat[3]
    return x
Kh40tiK
  • 2,276
  • 19
  • 29
1

In C#:

        static int fib(int n)
        {
            if (n < 2) return n;
            if (n == 2) return 1;
            int k = n / 2;
            int a = fib(k + 1);
            int b = fib(k);
            if (n % 2 == 1)
                return a * a + b * b;
            else
                return b * (2 * a - b);
        }
yosbel
  • 1,711
  • 4
  • 20
  • 32
1

Build an array Answer[100] in which you cache the results of fibonacci(n). Check in your fibonacci code to see if you have precomputed the answer, and use that result. The results will astonish you.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
  • No need to keep all of the answers, only the last two. – Ben313 Jul 29 '10 at 20:57
  • @Ben313: I think you're right. It isn't in the spirit of memoization in which you just store previously computed results in the hopes they'll get reused. With your scheme, you actually have to think :-} By cacheing them all, you don't have to think hard and it just works. The full cache will produce the *set* of answers somewhat more quickly, although I'll agree that for Fib it probably doesn't matter. Nice catch anyway. – Ira Baxter Jul 30 '10 at 21:28
1

Are you guaranteed that, as in your example, the input will be given to you in ascending order? If so, you don't even need memoization; just keep track of the last two results, start generating the sequence but only display the Nth number in the sequence if N is the next index in your input. Stop when you hit index 0.

Something like this:

int i = 0;
while ( true ) {
    i++; //increment index
    fib_at_i = generate_next_fib()
    while ( next_input_index() == i ) {
        println fib_at_i
}

I leave exit conditions and actually generating the sequence to you.

Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • Even if they're not sorted, you could load them into an array, sort a list of pointers into that array (not the array, so you don't destroy the original order), and compute Fibonacci numbers for the sorted list, then map them back to the original positions. If you're planning to support large values of `n` with some sort of bigint approach, this will be much more efficient than memoization since you only need to keep 2 bigints, rather than potentially thousands of them. – R.. GitHub STOP HELPING ICE Jul 27 '10 at 06:30
0

use any of these: Two Examples of recursion, One with for Loop O(n) time and one with golden ratio O(1) time:

private static long fibonacciWithLoop(int input) {
    long prev = 0, curr = 1, next = 0;      
    for(int i = 1; i < input; i++){
        next = curr + prev;
        prev = curr;
        curr = next;
    }
    return curr;
}

public static long fibonacciGoldenRatio(int input) {
    double termA = Math.pow(((1 + Math.sqrt(5))/2), input);
    double termB = Math.pow(((1 - Math.sqrt(5))/2), input);
    double factor = 1/Math.sqrt(5);
    return Math.round(factor * (termA - termB));
}

public static long fibonacciRecursive(int input) {
    if (input <= 1) return input;
    return fibonacciRecursive(input - 1) + fibonacciRecursive(input - 2);
}

public static long fibonacciRecursiveImproved(int input) {
    if (input == 0) return 0;
    if (input == 1) return 1;
    if (input == 2) return 1;
    if (input >= 93) throw new RuntimeException("Input out of bounds");
    // n is odd
    if (input % 2 != 0) {
        long a = fibonacciRecursiveImproved((input+1)/2);
        long b = fibonacciRecursiveImproved((input-1)/2);
        return a*a + b*b;
    }

    // n is even
    long a = fibonacciRecursiveImproved(input/2 + 1);
    long b = fibonacciRecursiveImproved(input/2 - 1);
    return a*a - b*b;
}
Vivek
  • 1,316
  • 1
  • 13
  • 23
0
using namespace std;

void mult(LL A[ 3 ][ 3 ], LL B[ 3 ][ 3 ]) {

     int i,

         j,

         z;

     LL C[ 3 ][ 3 ];

     memset(C, 0, sizeof( C ));

     for(i = 1; i <= N; i++)

         for(j = 1; j <= N; j++) {

             for(z = 1; z <= N; z++)

                 C[ i ][ j ] = (C[ i ][ j ] + A[ i ][ z ] * B[ z ][ j ] % mod ) % mod;
         }

     memcpy(A, C, sizeof(C));
};

void readAndsolve() {

    int i;

    LL k;

    ifstream I(FIN);
    ofstream O(FOUT);

    I>>k;

    LL A[3][3];
    LL B[3][3];

    A[1][1] = 1; A[1][2] = 0;
    A[2][1] = 0; A[2][2] = 1;

    B[1][1] = 0; B[1][2] = 1;
    B[2][1] = 1; B[2][2] = 1;

    for(i = 0; ((1<<i) <= k); i++) {

          if( k & (1<<i) ) mult(A, B);

          mult(B, B);
    }

    O<<A[2][1];
}

//1,1,2,3,5,8,13,21,33,...

int main() {

    readAndsolve();

    return(0);
}
Praveen Gowda I V
  • 9,569
  • 4
  • 41
  • 49
Adrian Statescu
  • 89
  • 1
  • 1
  • 7
0
public static int GetNthFibonacci(int n)
    {
        var previous = -1;
        var current = 1;
        int element = 0;

        while (1 <= n--)
        {
            element = previous + current;
            previous = current;
            current = element;
        }

        return element;
    }
Rajnikant
  • 2,176
  • 24
  • 23
0

You can reduce the overhead of the if statement: Calculating Fibonacci Numbers Recursively in C

Community
  • 1
  • 1
ford
  • 1,839
  • 3
  • 20
  • 38
0

First of all, you can use memoization or an iterative implementation of the same algorithm.

Consider the number of recursive calls your algorithm makes:

fibonacci(n) calls fibonacci(n-1) and fibonacci(n-2)
fibonacci(n-1) calls fibonacci(n-2) and fibonacci(n-3)
fibonacci(n-2) calls fibonacci(n-3) and fibonacci(n-4)

Notice a pattern? You are computing the same function a lot more times than needed.

An iterative implementation would use an array:

int fibonacci(int n) {
    int arr[maxSize + 1]; 
    arr[1] = arr[2] = 1; // ideally you would use 0-indexing, but I'm just trying to get a point across
    for ( int i = 3; i <= n; ++i )
        arr[i] = arr[i - 1] + arr[i - 2]; 

    return arr[n];
}

This is already much faster than your approach. You can do it faster on the same principle by only building the array once up until the maximum value of n, then just print the correct number in a single operation by printing an element of your array. This way you don't call the function for every query.

If you can't afford the initial precomputation time (but this usually only happens if you're asked for the result modulo something, otherwise they probably don't expect you to implement big number arithmetic and precomputation is the best solution), read the fibonacci wiki page for other methods. Focus on the matrix approach, that one is very good to know in a contest.

IVlad
  • 43,099
  • 13
  • 111
  • 179
0
#include<stdio.h>

 int g(int n,int x,int y)
   {
   return n==0 ? x : g(n-1,y,x+y);}

 int f(int n)
   {
   return g(n,0,1);}

 int main (void)
   {  
   int i;
   for(i=1; i<=10 ; i++)
     printf("%d\n",f(i)
   return 0;
   }
0

In the functional programming there is a special algorithm for counting fibonacci. The algorithm uses accumulative recursion. Accumulative recursion are used to minimize the stack size used by algorithms. I think it will help you to minimize the time. You can try it if you want.

int ackFib (int n, int m, int count){
    if (count == 0)
        return m;
    else
        return ackFib(n+m, n, count-1);
}



int fib(int n)
{
 return ackFib (0, 1, n+1);
}
Govan
  • 2,079
  • 4
  • 31
  • 53
0

This is similar to answers given before, but with some modifications. Memorization, as stated in other answers, is another way to do this, but I dislike code that doesn't scale as technology changes (size of an unsigned int varies depending on the platform) so the highest value in the sequence that can be reached may also vary, and memorization is ugly in my opinion.

#include <iostream>

using namespace std;

void fibonacci(unsigned int count) {
   unsigned int x=0,y=1,z=0;
   while(count--!=0) {
      cout << x << endl;  // you can put x in an array or whatever
      z = x;
      x = y;
      y += z;
   }
}

int main() {
   fibonacci(48);// 48 values in the sequence is the maximum for a 32-bit unsigend int
   return 0;
}

Additionally, if you use <limits> its possible to write a compile-time constant expression that would give you the largest index within the sequence that can be reached for any integral data type.

zackery.fix
  • 1,786
  • 2
  • 11
  • 20
  • 1
    While memorisation may be great for poems and multiplication tables, one mechanism to not recompute function values seems to be termed memoization. – greybeard Dec 13 '15 at 15:40
-1
#include<stdio.h>
main()
{
 int a,b=2,c=5,d;
   printf("%d %d ");
do
{
   d=b+c;
     b=c;
    c=d;
   rintf("%d ");
  }
Cilvan
  • 9
  • 2