-1

Solved:

I feel so stupid. GMP is fine and it was my oversight. After using size_t mpz_sizeinbase (const mpz_t op, int base), I realised my char array I used to copy the result into was too small. Increasing it size solved it. Thanks for the help!


My task is to write a C program which calculates the elements of the Fibonacci Sequence from the 1024th element to the 1048576th element (from the 10th power of 2 to the 20th power of 2, increasing by the power of 2). For this I'm using GMP library to handle the numbers. The problem is, that around the 17th power of 2, the number is so big, that even GMP can't handle it, which means I should use malloc().

Here is my main() (I modified the pasted code by taking out unnecessary parts like writing to file and time measurements which will be used for another part of the program):

int main(){
    int powersOfTwo[11];
    char res[10000];
    char *c;
    c = res;

    for(int i = 0; i < 11; i++){
        powersOfTwo[i] = normalPower(2,i+10);
    }
    for(int i = 0; i < 11; i++){
        fibo(c, powersOfTwo[i]);
        printf("The %d th element of Fibonacci is %s\n",powersOfTwo[i],res);
        memset(res, 0, sizeof res);
    }

    return 0;
} 

Now here is the simple normalPower function (Doesn't really have anything to do with the problem just for the sake of clarity):

int normalPower(int n1, int n2){
    if(n2 == 0){
        return 1;
    }else{
        int temp = n1;
        for(int i = 1; i < n2; i++){
            temp *= n1;
        }
        return temp;
    }
}

And now the problem, the fibo function:

void fibo(char *c, int n){
    mpz_t *fib1;
    mpz_t *fib2;
    mpz_t *temp;

    fib1 = (mpz_t *) malloc(101000000 * sizeof(mpz_t));
    fib2 = (mpz_t *) malloc(101000000 * sizeof(mpz_t));
    temp = (mpz_t *) malloc(101000000 * sizeof(mpz_t));

    if (NULL == fib1 || NULL == fib2 || NULL == temp){
      printf("ERROR: Out of memory\n");
    }
    mpz_init(*fib1);
    mpz_init(*fib2);
    mpz_init(*temp);

    mpz_set_str(*fib1,"0",10);
    mpz_set_str(*fib2,"1",10);

    int i;
    if(n == 0){
      char *d = mpz_get_str(NULL,10,*fib1);
      strcpy(c,d);
    }

    if(n == 1){
      char *d = mpz_get_str(NULL,10,*fib2);
      strcpy(c,d);
    }

    if(n > 1){
      for(i = 1; i < n; i++){
          mpz_set(*temp, *fib2);
          mpz_add(*fib2, *fib1, *fib2);
          mpz_set(*fib1,*temp);

      }
      char *d = mpz_get_str(NULL,10,*fib2);
      strcpy(c,d);
    }

    free(fib1);
    free(fib2);
    free(temp); 
}

Originally I used simply mpz_t-s, initing them and mpz_clear()-ing them in the end, no pointers and malloc(), but that led to Segmentation fault (core dumped) error after calculating the 2 on the power of 17(-ish) element. This was a solution I found on the Internet and this was almost the biggest number I could allocate, still nothing changes, the program stops at the same point with the same error message. I also tried to use mp_set_memory_functions() and creating a custom mallocWrapper() and giving it the GMP, but that didn't seem to work either. Of course I'm 99% sure, it's because I'm new to GMP and relative new to using malloc() so my code is probably making most of you tearing your hair out right now and I apologise for that.

So basically my question is: How should I use malloc() to get enough memory for the numbers?

Thanks for all the help in advance!

  • 2
    Argh, the code makes no sense... – Marc Glisse Nov 04 '15 at 20:54
  • Why not use the `pow` function instead of the `normalPower` function? The `pow` function is optimized . – lost_in_the_source Nov 04 '15 at 20:55
  • You don't need to *explicitly* `malloc` for one GMP bignum. The GMP library handles its internal memory allocation. You really should spend hours reading its documentation – Basile Starynkevitch Nov 04 '15 at 20:56
  • 1
    As a beginner, you really should use C++, which hides most of the pain for you. `#include `, then use the type `mpz_class` like you would use int, except that it magically has infinite precision. – Marc Glisse Nov 04 '15 at 20:57
  • @stackptr that's because I'm stupid, and completely forgot that exists. Maybe my brain was too occupied, but thanks for reminding me, going to fix it. – FieryHammer Nov 04 '15 at 21:02
  • @MarcGlisse I'd really like to as I saw it as a solution, but unfortunatelly the prof at my uni really wants us to write this in C. – FieryHammer Nov 04 '15 at 21:03
  • Did you take time to read the documentation of GMP? – Basile Starynkevitch Nov 04 '15 at 21:05
  • @BasileStarynkevitch I did, but still this problem persists and anywhere I looked people solved similar issues by using malloc and telling GMP how much space to use. – FieryHammer Nov 04 '15 at 21:11
  • Then, compile with all warnings & debug info (`gcc -Wall -Wextra -g`) -perhaps not only your code, but GMPlib itself. Use the debugger (`gdb`) and `valgrind` ; my first feeling is that your code does not smell very good. – Basile Starynkevitch Nov 04 '15 at 21:16
  • 1
    Would https://gmplib.org/manual/Number-Theoretic-Functions.html#index-mpz_005ffib_005fui be considered cheating? – Marc Glisse Nov 04 '15 at 21:27
  • @MarcGlisse Probably, but if all fails, I'm going to check it out, maybe it can help some way. – FieryHammer Nov 04 '15 at 21:33

2 Answers2

0

These lines:

mpz_t *fib1;
mpz_t *fib2;
mpz_t *temp;

fib1 = (mpz_t *) malloc(101000000 * sizeof(mpz_t));
fib2 = (mpz_t *) malloc(101000000 * sizeof(mpz_t));
temp = (mpz_t *) malloc(101000000 * sizeof(mpz_t));

look very wrong to me (and your entire source code smells very bad, you should drop it). It seems that you want to allocate 101000000 different bignums, and I don't understand why you need that much.

Read carefully the documentation of GMPlib and the definition of Fibonnaci numbers. You only need a few mpz_t (very probably you need less than half a dozen of mpz_t variables), not many millions of them. Think about the mathematic definition of Fibonacci before coding your program. Notice that if you know Fib(10000) and Fib(10001) computing Fib(10002) is easy with GMPlib and then you don't need Fib(10000) any more and you can print Fib(10002) as soon as it has been computed. Be aware that you can use mpz_set to assign GMP big integers.

(you really should start rewriting your program from scratch after having thinking on the math; you can dump your existing code)

Don't forget to initialize every variable, to call mpz_init appropriately.

Compile with all warnings and debug info (gcc -Wall -Wextra -g). Use the debugger (gdb) and valgrind and perhaps -fsanitize= debugging options

As far as I understand you don't need even a single explicit call to malloc in your code (of course, internally GMPlib is using malloc).

(BTW, as a student it is helpful to assume that your exercise is doable quite easily)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • My original codes used simply mpz_t-s and mpz_clear()-ing as I have mentioned. I understand that I use malloc in a bad way in my code but I still need a way to increase the memory size mpz_t uses, as by default it won't allocate enough memory after a while. – FieryHammer Nov 04 '15 at 21:28
  • 1
    That should go into your question, not as a comment. – Basile Starynkevitch Nov 04 '15 at 21:29
  • Alright, you were right, and I feel soooo stupid. It turned out that everything worked fine except this: char res[10000]; was too small. I needed it to use more space. – FieryHammer Nov 05 '15 at 18:05
-3

If GMP library can't handle it, look into using a char* with your algorithm to take care of the number. You can easily out do anything GMP can support.

scerrecrow
  • 259
  • 1
  • 9