0

I wrote a small program to compute Fibonacci numbers:

#include <stdio.h>

int main()
{
    int first, second, final;

    first = 0;
    second = 1;
    printf("0\n1\n"); /* I know this is a quick fix, but the program still works */
    while (final <= 999999999999999999) {
        final = first + second;
        first = second;
        second = final;
        printf("%d\n", final);
    }
}

Is there any way to increase the speed in which this program computes these calculations? Could you possible explain the solution to me (if it exists)?

Thanks.

  • 4
    Please first make your program correct, than increase its speed. – llllllllll Jan 29 '18 at 13:05
  • Your program has a bug: `final` is not initialized correctly before use. – user694733 Jan 29 '18 at 13:06
  • 5
    Pro-tip: Turn on all your compiler warnings. They are a valuable source of hints for debugging. The posted code yields this warning: "comparison is always true due to limited range of data type" and points to this piece of code: `while (final <= 999999999999999999)` – Morten Jensen Jan 29 '18 at 13:06
  • Thanks for the replies! liliscent, I can't quite find a way to make my program correct, even when I move the printf (in the loop) to the beginning of the loop. I've initialized final now, thanks user! Thanks Morten, I've turned on all of my compiler warnings. Is the "limited data range" responsible for the slow calculations then? Thanks! – Serene Bison Jan 29 '18 at 13:13
  • check https://stackoverflow.com/questions/18172257/efficient-calculation-of-fibonacci-series ? – Antonin GAVREL Jan 29 '18 at 13:18
  • What do you mean by slow? Your program will probably loop forever! Is that your problem? Or do you actually mean "slow"? – Support Ukraine Jan 29 '18 at 13:34
  • 4
    A 32 bit unsigned int will only be able to fit the first 46 elements of the Fibonacci sequence. A 64 bit unsigned number will fit 93 first elements. Performance is not your problem. – Art Jan 29 '18 at 13:45
  • Yes! Run the program on a faster hardware. – bolov Jan 29 '18 at 13:55
  • actually my bad. First get rid of the Undefined Behavior then run the program on a faster hardware. – bolov Jan 29 '18 at 13:57
  • Compile with optimizations on. – Retired Ninja Jan 29 '18 at 14:38

4 Answers4

2

Of course it's possible! :)

First of all, please note you're using signed int for your variables, and max int on a 32 bit machine is 2,147,483,647 which is approx. 10^8 times smaller than the max number you're using, which is 999,999,999,999,999,999. I'll recommend to change the max num to INT_MAX (You'll need to include "limits.h")

Edit: In addition, as said in the comments to my answer, consider changing to unsigned int. you need only positive values, and the max number will be twice higher.

2nd Edit: That being said, when final will reach the closest it can to the limit in the condition, the next time its promoted, it'll exceed INT_MAX and will result in an overflow. That means here, that the condition will never be met. Better to just change the condition to the times you want the loop to run. Please note though, that any fibonacci number larger than the max numder that can be stored in your variable type, will result in an overflow.

Secondly, final isn't initialized. Write final = 0 to avoid errors.

I recommend turning on all the warnings in your compiler. It could catch many errors before they compile :) Also, I see no reason not to initialize the variables when you declare them. The value is already known.

Now for the speed of the program: I'm not sure to which extent you're willing to change the code, but the simplest change without changing the original flow, is to make less calls to printf().

Since printf() is a function that will wait for a system resource to become available, this is probably the most time consuming part in your code.

Maybe consider storing the output in a string, and lets say every 100 numbers print the string to the screen.

Try maybe to create a string, with a size of (10 (num of chars in an int) + 1 (new line char) )* 100 (arbitrary, based on when you'll want to flush the data to the screen)

Consider using sprintf() to write to a string in the inner loop, and strcat() to append a string to another string. Then, every 100 times, use printf() to write to the screen.

ATE
  • 76
  • 6
  • 1
    `I'll recommend to change the max num to INT_MAX`? If you mean `while (final <= INT_MAX)` it's a bad idea. I'm sure that will result in an endless loop... – Support Ukraine Jan 29 '18 at 13:49
  • @4386427 You're right of course, the meaning was `while (final < INT_MAX)` – ATE Jan 29 '18 at 13:54
  • 1
    That solution won't help as you'll get integer overflow and start printing negative values. The largest Fibonacci number for a 32 bit int is 1836311903. Going beyond that will just fail. There is really just 46 numbers to print.... Reducing the numbers of `printf` will probably help on execution time but a correct implementation will not execute for long so I doubt it is worth to do anything – Support Ukraine Jan 29 '18 at 13:59
  • @4386427 Yet again, you are right. The program *should* use some sort of big number type, that the OP should write. Also, the condition is bad, and will result in an overflow. I'll fix the answer to reflect this. – ATE Jan 29 '18 at 14:06
  • Thanks a lot for your help ATE! I learnt a lot from your response - really easy to follow (I'm new to programming - could you tell?). Thanks! – Serene Bison Jan 29 '18 at 14:39
  • The exit loop condition to prevent overflow of positive `int` is `while (first <= INT_MAX - second)` – chux - Reinstate Monica Jan 29 '18 at 15:34
2

As already stated in other answers, you have obvious two problems. 1) The missing initialization of final and 2) that your loop condition will result in an endless loop due to 999999999999999999 being larger than any integer value.

The real problem here is that you use a fixed number in the condition for the while.

How do you know which number to use so that you actually calculates all the Fibonacci numbers possible for the used integer type? Without knowing the numbers in advance you can't do that! So you need a better condition for stopping the loop.

One way of solving this to check for overflow instead - like:

while (second <= (INT_MAX - first)) {  // Stop when next number will overflow

The above approach prevents signed overflow by checking whether the next first + second will overflow before actually doing the first+second. In this way signed overflow (and thereby UB) is prevented.

Another approach is to use unsigned integers and deliberately make an overflow (which is valid for unsigned int). Using unsigned long long that could look like:

unsigned long long first, second, next;

first = 1;
second = 1;
printf("1\n1\n");

next = first + second;
while (next > second) {     // Stop when there was an overflow
    printf("%llu\n", next);
    first = second;
    second = next;
    next = first + second;
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

Speed isn't your problem. You have an infinite loop:

while (final <= 999999999999999999) {

final has type int. Most likely int is 32-bit on your system, which means the maximum value it can hold is 2147483647. This will always be smaller than 999999999999999999 (which is a constant of type long long), so the loop never ends.

Change the datatype of your variables to long long and the loop will terminate after about 87 iterations. Also, you'll need to change your printf format specifier from %d to %lld to match the datatype printed.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • I've often seen the 2.1B number other places too - I now know its origins in terms of technology. Thanks for introducing me to the long long datatype, that's very helpful! – Serene Bison Jan 29 '18 at 14:40
0

Why are you asking this question?

If it's the intention to increase the performance, you might go for the formula of the n-th Fibonacci number, which is something like:

((1+v5)/2)^n + ((1-v5)/2)^n, something like that (v5 being the square root of 5).

If it's about learning to increase performance, you might do a code review or use performance diagnostics tools.

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • 1
    Is using that formula really likely to run faster than just remembering the previous two numbers and adding them? Sure, if you only want to calculate the 40th number then the standard formula of adding the previous two might require more calculations but if you are calculating all of them anyway then I'd be surprised if the more complicated formula had a particular performance incrase (though I would be interested in your explanation of why this formula will be faster). – Chris Jan 29 '18 at 16:30
  • function power(x, n ) = power(x,n/2)*power(x,n/2) computing power n takes just log n / log 2 basic multiplication while the traditional loop take n basic addition – Frostic Mar 19 '18 at 22:19