skip to Main Content

The following code works fine (compiles, assert statement gives true) under Linux/Debian (g++ 10.2), but refuses to work under Windows (mingw64 g++ 12.2.0). It’s basically just supposed to assign UINT64_MAX to a mpf_class from the gmp library, but it seems gmp’s mpf_class defines no constructor and no operators for uint64_t, which is unsigned long long int in the windows environment I’m trying to work with here. I bet there is a simple workaround I’m not seeing right now, because it’s friday and late, correct?

#include <gmpxx.h> // link with gmp + gmpxx
#include <string>

/// Helper to convert mpf_class to std::string
[[nodiscard]] inline std::string mpf_class_to_str(const mpf_class& num) {
    mp_exp_t exponent(1);
    return num.get_str(exponent, 10);
}

int main() {
    mpf_class y = UINT64_MAX; // defined in my mingw64 as 0xffffffffffffffffULL
    //            ^
    //            |  adding no cast -> compile error
    //               adding (unsigned int) cast -> compiles, but assertion below false
    //               adding (uint64_t) cast -> compile error

    y *= UINT64_MAX; // UINT64_MAX²
    assert(mpf_class_to_str(y) == "340282366920938463426481119284349108225");
}

The compile error g++ gives me is:

error: conversion from 'long long unsigned int' to 'mpf_class' is ambiguous
   31 |             mpf_class y = UINT64_MAX;
      |                           ^~~~~~~~~~

and then it lists all candidates, which basically are (taken from gmpxx.h instead of the error log):

#define __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS      
  __gmp_expr(signed char c) { init_si(c); }     
  __gmp_expr(unsigned char c) { init_ui(c); }       
  __gmp_expr(signed int i) { init_si(i); }      
  __gmp_expr(unsigned int i) { init_ui(i); }        
  __gmp_expr(signed short int s) { init_si(s); }    
  __gmp_expr(unsigned short int s) { init_ui(s); }  
  __gmp_expr(signed long int l) { init_si(l); }     
  __gmp_expr(unsigned long int l) { init_ui(l); }   
  __gmp_expr(float f) { init_d(f); }            
  __gmp_expr(double d) { init_d(d); }

If I manipulate that header adding the line __gmp_expr(unsigned long long int l) { init_ui(l); } all is well except this is too dirty of a fix even for me.

2

Answers


  1. Chosen as BEST ANSWER

    Besides patching the gmp library as suggested in user17732522's answer it's also possible to get my example to work by using a conversion helper function. Something like this:

    /// Helper for converting anything to mpf_class.
    namespace bigdec {
    template<typename T> [[nodiscard]] inline
    mpf_class get(const T& num) {
        std::stringstream ss;
        ss << num;
        mpf_class bigdec;
        bigdec.set_str(ss.str(), 10);
        return bigdec;
    }}
    

    And changing the usage accordingly:

    int main() {
        mpf_class y = bigdec::get(UINT64_MAX); // <- here
        y *= bigdec::get(UINT64_MAX);          // <- and here
        assert(mpf_class_to_str(y) == "340282366920938463426481119284349108225");
    }
    

    Now it compiles and the assertion gives true in both - my Linux and Windows environment.


  2. mpz_class cannot be constructed from a (unsigned) long long. That is also stated in the documentation.

    The library does not support (unsigned) long long. See the mailing list thread here (and several older ones). In the answer Marc Glisse also points out that this is mainly an issue on Windows.

    He also suggested a patch for support of the C++ initialization/conversion part of the problem here, but I couldn’t find it on gmp’s public development repository yet. As he points out in the message, this would not cover arithmetic operations and such though.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search