Search code examples
cfibonaccigmp

Fibonacci function using GMP 5.0.2 in C


I wrote a Fibonacci function using types and functions from the GMP 5.0.2 Library. But I keep getting error when I compile it. Below are the error and the code:

main.c:4:7: error: ‘fib’ declared as function returning an array
main.c: In function ‘main’:
main.c:21:10: error: incompatible types when assigning to type ‘mpz_t’ from type ‘int’
main.c: At top level:
main.c:32:7: error: ‘fib’ declared as function returning an array
main.c: In function ‘fib’:
main.c:33:28: warning: return makes integer from pointer without a cast [enabled by default]
main.c:44:3: warning: passing argument 2 of ‘__gmpz_set’ makes pointer from integer without a cast [enabled by default]
/usr/local/include/gmp.h:1074:21: note: expected ‘mpz_srcptr’ but argument is of type ‘int’
main.c:45:3: warning: passing argument 2 of ‘__gmpz_set’ makes pointer from integer without a cast [enabled by default]
/usr/local/include/gmp.h:1074:21: note: expected ‘mpz_srcptr’ but argument is of type ‘int’
main.c:47:3: error: too few arguments to function ‘__gmpz_add’
/usr/local/include/gmp.h:696:21: note: declared here

and the code is

#include <stdio.h>
#include <gmp.h>

mpz_t fib (mpz_t, const mpz_t);

int main (void) {
    printf("Before anything\n"); // debugging

    mpz_t FOUR; mpz_init(FOUR); mpz_add_ui(FOUR, FOUR, 4);

    printf("Declare FOUR, initilize it, set it to 4\n"); // debugging

    mpz_t N; mpz_init(N); mpz_add_ui(N, N, 5);

    printf("Declare N, initilize it, set it to 5\n"); // debugging

    mpz_t fibFive; mpz_init(fibFive);

    printf("Declare fibFive, initilize it\n"); // debugging

    fibFive = fib(N, FOUR);

    printf("After calling the fib function on fibFive\n"); // debugging

    gmp_printf("5th fibonacci number is %Zd\n", fibFive);

    printf("the end\n"); // debugging

    return 0;
}

mpz_t fib (mpz_t n, const mpz_t baseCase) {
    if (mpz(n, baseCase) < 0) return n;
    else {
        mpz_t a, b;
        mpz_t t1, t2;

        mpz_init(a); mpz_init(b);
        mpz_init(t1); mpz_init(t2);

        mpz_sub_ui(t1, n, 2);
        mpz_sub_ui(t2, n, 1);

        mpz_set(a, fib(t1, baseCase));
        mpz_set(b, fib(t2, baseCase));

        return mpz_add(a, b);
    }
}

And for the compilation I used gcc main.c -lgmp

NOTE: I read the manual of GMP and I used the functions in the code from the Integer Function manual GMP 5.0.2 Manual - Integer Functions


Solution

  • The relevant part of gmp.h (I don't know the minor version I have installed, but it's been the same in GMP 4, and I don't expect it to change soon) is

    typedef struct
    {
      int _mp_alloc;            /* Number of *limbs* allocated and pointed
                                   to by the _mp_d field.  */
      int _mp_size;             /* abs(_mp_size) is the number of limbs the
                                   last field points to.  If _mp_size is
                                   negative this is a negative number.  */
      mp_limb_t *_mp_d;         /* Pointer to the limbs.  */
    } __mpz_struct;
    
    #endif /* __GNU_MP__ */
    
    
    typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
    typedef __mpz_struct mpz_t[1];
    

    So an mpz_t is an array of length one containing an __mpz_struct. That's the reason for

    main.c:4:7: error: ‘fib’ declared as function returning an array

    and the likes. Without prototype, the compiler apparently assumes implicit int, thus

    fibFive = fib(N, FOUR);
    

    causes

    main.c:21:10: error: incompatible types when assigning to type ‘mpz_t’ from type ‘int’

    To fix it, you must pass mpz_ts as out-parameters to your function(s), with minimal changes (not that your indices are off, F(0) = 0 conventionally):

    #include <stdio.h>
    #include <gmp.h>
    
    void fib (mpz_t, mpz_t, const mpz_t);
    
    int main (void) {
        printf("Before anything\n"); // debugging
    
        mpz_t FOUR; mpz_init(FOUR); mpz_add_ui(FOUR, FOUR, 4);
    
        printf("Declare FOUR, initilize it, set it to 4\n"); // debugging
    
        mpz_t N; mpz_init(N); mpz_add_ui(N, N, 5);
    
        printf("Declare N, initilize it, set it to 5\n"); // debugging
    
        mpz_t fibFive; mpz_init(fibFive);
    
        printf("Declare fibFive, initilize it\n"); // debugging
    
        fib(fibFive, N, FOUR);
    
        printf("After calling the fib function on fibFive\n"); // debugging
    
        gmp_printf("5th fibonacci number is %Zd\n", fibFive);
    
        printf("the end\n"); // debugging
    
        return 0;
    }
    
    void fib (mpz_t res, mpz_t n, const mpz_t baseCase) {
        if (mpz_cmp(n, baseCase) < 0){
            mpz_set(res,n);
        } else {
            mpz_t a, b;
            mpz_t t1, t2;
    
            mpz_init(a); mpz_init(b);
            mpz_init(t1); mpz_init(t2);
    
            mpz_sub_ui(t1, n, 2);
            mpz_sub_ui(t2, n, 1);
    
            fib(a, t1, baseCase);
            fib(b, t2, baseCase);
    
            mpz_add(res, a, b);
        }
    }