简体   繁体   中英

Fibonacci function with big number (i.e. 1000 digits) in C

EDIT: I replace: carry = (x-(x%10))%10; by: carry = x/10;

And I add at the end of the while loop in addition(): if(carry) f3[i] = carry;

Thanks to FalconUSA & M_Oehm ! :)

I'm working on problem 25 of Project Euler (beware spoilers), and while the fibonacci function isn't really a problem I've difficulties to implement a way to store huge number (like there a 1000 digits).

So i've tried (as i learnt on the web) to deal with it with array, but the program is running indefinitely. My problem is probably in addition() or length().

Any ideas about it ?

#include <stdio.h>
#include <string.h>

int length(int *nbr) // number of digits of my number
{
    int len = 0, c = 0;

    while(nbr[c] >= 0) {
        len++;
        c++;
    }
    return len;
}

int addition(int *f1, int *f2, int *f3, int siz) // add f1+f2 and store it in f3
{
    int carry =0, i =0;
    int x;

    memset ( f3, -1, siz*sizeof(int));

    while ( (f1[i] >= 0) || (f2[i] >= 0) ) {
        if(f1[i]<0) {
            x = f2[i] + carry;
        }
        else if(f2[i]<0) {
            x = f1[i] + carry;
        }
        else {
            x = f1[i] + f2[i] + carry;
        }
        f3[i] = x%10;
        carry = (x-(x%10))%10;
        i++;
    }

    return 0;
}

int copy_arr(int *dest, int *or, int siz) //copy array "or" into "dest"
{
    int c = 0;
    memset( dest, -1, siz*sizeof(int));

    while( c < siz ) {
        dest[c] = or[c];
        c++;
    }

    return 0;
}

int fibo(int siz) //fibonacci function
{
    int f1[siz],f2[siz],f3[siz];
    memset( f1, -1, siz*sizeof(int));
    memset( f2, -1, siz*sizeof(int));
    memset( f3, -1, siz*sizeof(int));

    int n = 2;

    f1[0] = f2[0] = 1;


    while (length(f1) <= siz) {
        n++;
        addition( f1, f2, f3, siz);
        copy_arr( f2, f1, siz);
        copy_arr( f1, f3, siz);
    }

    printf("%d\n", n);

    return 0;
}


int main() // siz's value is the number of digits I desire for my fibonacci number
{
    int siz=1000;

    fibo(siz);

    return 0;
}

You could use GMP multiple precision library: https://gmplib.org . You may also want to check Fibonacci section: https://gmplib.org/manual/Fibonacci-Numbers-Algorithm.html .

UPDATE You may also want to check this post, which demonstrates how to implement fast Fibonacci from scratch: https://www.anfractuosity.com/2012/10/24/fib-calculation-with-gmp .

Pros of using GMP are that you will have a really fast and elaborated algorithms, written by people who know what they do. GMP is extremely fast (it is partially written in assembler and makes a deep use of various algorithms), mature and stable library. Whenever you need to work with big numbers, it's always a good idea to use GMP.

Well, seems like your problem is in this line:

carry = (x - x%10) % 10;

it should be just

carry = x - x%10;

or

carry = x / 10;

which is equivalend in this case.

UPDATE: also, in line

 while ( (f1[i] >= 0) || (f2[i] >= 0) ) {

if the size of f1 is siz and the size of f2 is also siz , then you'll reach the element f1[siz] , or even further, which is out of range . So, you should declaring

int f1[siz+1], f2[siz+1], f3[siz+1]

and you should setting siz+1 edges everywhere:

memset( fi, -1, (siz+1)*sizeof(int)); // where 1 <= i <= 3

PS: if you only want to calculate that fibonacci number without integrating into some program that requires fast calculation, it's better to use Python or Java , because these languages have built-in long numbers support and their syntax are very easy and similar to C++ . And, as ghostmansd mentioned above, it's better to use GMP library if you're going to use C/C++ anyways.

There are several problems with your code.

Your numbers are terminated by a digit with the sentinel value −1. You need space for that extra digit, much like you need space for the null terminator in C strings. You should dimension your arrays to siz + 1 and initialise all values including the dummy value.

When you add two numbers, you never consider the last carry. That means that your numbers never get longer. Add this after the main lop in addition :

if (carry) f3[i] = carry;

Your method to determine the carry isn't correct, either. The carry are the excess digits to the left:

carry = x / 10;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM