views:

487

answers:

15

Hello! 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.

+11  A: 

You should probably look into memoization.

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

It has an explanation and a fib example right there

Xzhsh
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..
@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
+1  A: 

Can you post input.txt file and time limits? btw: This task is well know. Did you read the following http://www.ics.uci.edu/~eppstein/161/960109.html ?

iyalovoi
+4  A: 

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
I don't think calculating `fibonacci(500)` like this will work though :).
IVlad
Yes, it will overflow. I changed it to 50. Thanks for your comment :).
dcp
Now remove the useless code and replace it with `static const int memo[50] = { 0, 1, 1, 2, 3, 5, ... };`
R..
@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
+8  A: 

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

This issue has been discussed on stackoverflow before: http://stackoverflow.com/questions/360748/computational-complexity-of-fibonacci-sequence

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

sukru
+1  A: 

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
No need to keep all of the answers, only the last two.
Ben313
@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
A: 

Google is your friend:

http://www.chaos.org.uk/~eddy/craft/Fibonacci.html

Visage
A: 

You can reduce the overhead of the if statement: http://stackoverflow.com/questions/2170276/calculating-fibonacci-numbers-recursively-in-c/2170308#2170308

ford
A: 

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
+6  A: 

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
I think you are responding to a different question. This isn't even remotely related to fibonacci numbers.
A. Levy
@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
It is quite related to fibonacci numbers. For example, see algorithm 5 of: http://www.ics.uci.edu/~eppstein/161/960109.htmlThis 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
@A.Levy worked example here http://stackoverflow.com/questions/1525521/nth-fibonacci-number-in-sublinear-time/1526837#1526837
Pete Kirkham
Teodor Pripoae
maybe the best solution in this situation
swegi
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
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
+4  A: 

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

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

David Brunelle
+1 for the formula.
Brian
No recursion and no guarantee of exact results.
IVlad
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
@David Brunelle - no exact result because irrational numbers don't exist for a computer. There exist only rational approximations for those irrational numbers.
IVlad
@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
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
@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
@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
@IVlad: You can just use the right tool for the job, i.e. mathematica or maple or whatever math system you like
swegi
@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
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
@IVlad : That is not C code.
Brian
@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
@IVlad: At least maple has a C interface.
swegi
@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
@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
@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
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
@IVlad : Yes, but the power operations are on doubles, not `long long` s.
Brian
The original question used `int`, and I'm pretty sure `int` will overflow long before you hit the precision limits of `double`...
R..
+1  A: 

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
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..
+2  A: 

Use the golden-ratio

alt text

alt text

Anurag
This is a very bad idea if he needs exact results, which seems to be the case.
IVlad
Not necessarily, see the discussion on David Brunelle's post.
swegi
@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
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
@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
@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..
A: 
#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;
   }
gcc
+5  A: 

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.

Chris
+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..
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
A: 

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