2

I want to assign the values from 64 bit integers into mpz_class/mpz_t variables and later get 64 bit integers back. However GMP only provides this functionality for 32 bit and lower integers.

So how would I turn an 64 bit integer into a mpz_class/mpz_t variable and vice versa. (I need it for both signed and unsigned integers)

BrainStone
  • 3,028
  • 6
  • 32
  • 59
  • 1
    Maybe it could be done using `mpz_import` and `mpz_export`? – ProXicT Jul 30 '18 at 20:25
  • Excuse my stupid question, but for what is `rop` and `op`? Which of these recieves the value? And also with just one value the endianness shouldn't matter, right? This seems to work fine with unsigned ints, but what about signed ints? Edit: I now understand the difference between `rop` and `op` – BrainStone Jul 30 '18 at 20:50
  • 1
    I will create an answer for you :) – ProXicT Jul 30 '18 at 20:54
  • @BrainStone Endianess matters since your values are 8 bytes, just pick 0 for 'native' endianess – john Jul 30 '18 at 20:55
  • @john you are right. I meant the order (parameter). That really shouldn't matter, if I'm not mistaken. – BrainStone Jul 30 '18 at 21:06
  • I guess you are on windows? On other 64 bit OS, GMP does handle 64 bit integers (the interface uses `long`). – Marc Glisse Jul 30 '18 at 23:35
  • https://stackoverflow.com/q/6248723/1918193 – Marc Glisse Jul 30 '18 at 23:37

1 Answers1

2

This could be achieved with mpz_import() and mpz_export() functions.
Code sample (tested on LP64 data model):

using Type = int64_t;

// We start with some 64bit integer
const Type builtIn64 = std::numeric_limits<Type>::min();
std::cout << builtIn64 << '\n';

// Import the integer into the mpz_class
mpz_t mpzNum;
mpz_init(mpzNum);
mpz_import(mpzNum, 1, 1, sizeof(Type), 0, 0, &builtIn64);
if (builtIn64 < 0) {
    mpz_neg(mpzNum, mpzNum);
}
std::cout << mpz_class(mpzNum) << '\n';

// Export the mpz_t value to a buffer allocated by the function and given
// the word size, get also the number of words required to hold the value
const size_t wordSize = sizeof(Type);
size_t wordCount = 0;
void* outRaw = mpz_export(nullptr, &wordCount, 1, wordSize, 0, 0, mpzNum);

// Make sure that our integer type can still hold the value
if (wordCount == 1) {
    const Type out = *static_cast<Type*>(outRaw);
    std::cout << out << '\n';
}

// Free the allocated memory by mpz_export
void (*freeFunction)(void*, size_t);
mp_get_memory_functions(nullptr, nullptr, &freeFunction);
freeFunction(outRaw, wordCount * wordSize);

// Don't forget to free the allocated memory
mpz_clear(mpzNum);

LIVE DEMO

ProXicT
  • 1,903
  • 3
  • 22
  • 46
  • 1
    Since `mpz_export` returns an `uint64_t` array in this case, couldn't we just check the wordCount and if it's 1 just have `out = allocated[0]; delete[] allocated;`? – BrainStone Jul 30 '18 at 21:18
  • @BrainStone You are absolutely right, I've edited the answer. However, keep in mind that you cannot use `delete[]` to free the memory allocated by `mpz_export` as it is certainly not using `new` to allocate the memory. You cannot mix `new` with `free` and `malloc` with `delete`. It's much safer to get the `free()` function using the API. – ProXicT Jul 30 '18 at 21:30
  • @BrainStone I'm still looking in a way to tell `mpz_t` that it is a signed value. It works when you convert the `int64_t` to `mpz_t` and back, but `mpz_t` itself doesn't seem to handle the value as signed. – ProXicT Jul 30 '18 at 21:32
  • thank you! Also from what I read here: https://stackoverflow.com/a/5013661/1996022 it's better to use a `static_cast` here, since we know the `void*` is in reality a `uint64_t*` (or at least the words have the same size) – BrainStone Jul 30 '18 at 21:36
  • Yep, you are right, the condition `wordCount == 1` makes it possible :) – ProXicT Jul 30 '18 at 21:41
  • Got it working even with the negative numbers, see my edit ;-) – ProXicT Jul 30 '18 at 22:03