-2

I've been working on the Euler 29 problem for a few days and am having difficulty getting the mpz_t type to work correctly. The objective is to iterate through a^b for values of 2 <= a,b <= 100 and count the nonrepeat values.

Using vector I was able to store the values using pointers in an array like so:

mpz_t a;
mpz_init(a);
vector<mpz_t*> numbers;
numbers.push_back(&a);

However, when running the full program below you can see that after it inserts the first value 4, it doesn't insert any new values. This is because the temp value being compared to rop is not being set to what is already in the array, and instead is set to the value shared by rop.

#include <iostream>
#include <vector>
#include <chrono>
#include "gmp.h"

using namespace std;

int main()
{
    auto start = std::chrono::high_resolution_clock::now();
    
    int solution = 0;
    bool found = false;
    int r = 10;
    
    mpz_t rop;
    mpz_init(rop);
    
    mpz_t temp;
    mpz_init(temp);
    
    vector<mpz_t*> numbers;
    
    for(int a = 2; a <= 5; a++)
    {
        for(int b = 2; b <= 5; b++)
        {
            mpz_ui_pow_ui(rop, a, b);
            for(int i = 0; i < numbers.size(); i++)
            {
                cout << "i: " << i << endl;
                cout << "rop: ";
                mpz_out_str(stdout,10,rop);
                cout << endl;
                
                mpz_set(temp,*(numbers.at(i)));
                cout << " temp: ";
                mpz_out_str(stdout,10,temp);
                cout << endl;
                
                r = mpz_cmp(rop,temp);
                cout << " r: " << r << endl << endl;
                if(r == 0)
                {
                    found = true;
                    break;
                }
            }
            if(found == false)
            {
                numbers.push_back(&rop);
                solution++;
                cout << "pushed! " << endl << endl;
            }
            found = false;
        }
    }

    auto done = std::chrono::high_resolution_clock::now();
    cout << "Solution: " << solution << endl << endl;
    cout << "Program completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(done - start).count() << " milliseconds." << endl;
}

This line of code should be setting temp equal to 4 at the start of the forloop, but instead sets it equal to rop:

mpz_set(temp,*(numbers.at(i)));

Since the problem clearly has to do with the fact I'm using pointers and passing the actual address in memory to store these mpz_t variables, how can I change the code so that it is able to work properly? I'm under the impression using the function mpz_clear(rop) after each push_back to the numbers vector wouldn't work as it releases the address from memory.

MFerguson
  • 1,739
  • 9
  • 17
  • 30
  • 2
    `numbers.push_back(&rop);`: So your `numbers` vector is populated entirely with pointers to the same object `rop`, just as you observed. Perhaps you wanted a vector of `mpz_t` instead of `mpz_t *`? – Nate Eldredge Sep 30 '21 at 20:41
  • 1
    GMP comes with a C++ wrapper (gmpxx) and several others are available elsewhere (boost, etc), I don't know why so many people still try to use GMP directly in C++. – Marc Glisse Oct 01 '21 at 09:31

1 Answers1

0

I figured out that due to the way mpz_t variables work the mpz_set function does not work with a pointer to mpz_t type variables as a parameter.

Instead, I was able to get the program to work by assigning the mpz_get_str function to a string and pushing that to a vector of strings to check for repeat values.

mpz_t rop;
mpz_init(rop);

char * num;
vector<string> numbers;

num = mpz_get_str(num,10,rop)
numbers.push_back(num);
MFerguson
  • 1,739
  • 9
  • 17
  • 30