Reputation: 58
I am porting my c++ code from Linux to Windows using MSYS2 (64 bit). The key library is GNU MP (gmplib). The following code gives wrong results in MSYS2/MinGW64 environment while in Ubuntu works fine. Apparantly there is an unwanted conversion from 64 bit integer to 32 bit unteger when using mpz_set_ui
function.
#include <iostream>
#include <gmp.h>
int main() {
std::cout << "GMP version: " << __gmp_version << std::endl;
std::cout << "GMP_LIMB_BITS: " << GMP_LIMB_BITS << std::endl;
unsigned long long a = UINT64_MAX;
std::cout << a << std::endl;
mpz_t mpz;
mpz_init(mpz);
mpz_set_ui(mpz, a);
unsigned long long b = mpz_get_ui(mpz);
std::cout << b << std::endl;
}
Ubuntu correct output:
GMP version: 6.2.0
GMP_LIMB_BITS: 64
18446744073709551615
18446744073709551615
MSYS2/MinGW64 unexpected conversion:
GMP version: 6.2.1
GMP_LIMB_BITS: 64
18446744073709551615
4294967295
Steps to reproduce the behavior:
Getting Started
from https://www.msys2.org/ run in MSYS2 environment:pacman -Syu
pacman -Su
pacman -S --needed base-devel mingw-w64-x86_64-toolchain
g++ -MT .o/main.o -MD -MP -MF .d/main.Td -std=c++17 -g -Wall -Wextra -pedantic -c -o .o/main.o main.cpp mv -f .d/main.Td .d/main.d g++ -static -o main .o/main.o -lgmp
main.d points to C:/msys64/mingw64/include/gmp.h as expected and I verified that C:\msys64\mingw64\lib\libgmp.a is used for linking and no other version of gmplib.a is present in subfolders of C:/msys64
I also did custom build of GNU MP library using:
./configure
make
make install
However the unwanted conversion ramained the same. I probably miss something basic, but I am at a loss. This is my first question on Stackoverflow and I would really appreciate your help.
Upvotes: 4
Views: 258
Reputation: 16419
The mpz_get_ui()
function returns an unsigned long
, NOT an unsigned long long
.
On Linux/GCC, unsigned long
is a 64-bit value, however the C++ standard only requires that unsigned long
support values up to 4'294'967'295
, which can be satisfied by a 32-bit integer. Linux allows larger values, but MSVC and MinGW on Windows will use a 32-bit integer for unsigned long
. This means that on Windows, your 64-bit input value in mps_set_ui()
is downgraded to a 32-bit value.
Therefore the behavior on both compilers is correct, you've tripped over a platform-specific implementation detail.
If you wish to allow use of 64-bit integers everywhere, you should use fixed bit-width integer types (e.g. uint64_t
instead of unsigned long
), but that stil won't allow you to specify 64-bit integers mp_set_ui
on Windows unfortunately.
Upvotes: 3