If nobody complains and I don't see something horribly flawed in the
patch, I am going to push this version, which for now only adds
initialization and assignment from long long when in C++11 mode (I expect
we will remove support for C++ compilers without long long in the next
release, but for now it is conditional).
It doesn't add interoperability for other operations, so z+1LL will still
fail. Handling all operations can require a lot more code, depending on
how it is done, and can be done later. Conversions are already quite
useful for users, in particular they are sufficient to let Eigen use
mpq_class as a custom scalar type on windows.
--
Marc Glisse
diff -r 88e4445a72d1 doc/gmp.texi
--- a/doc/gmp.texi Mon Apr 18 16:19:20 2022 +0200
+++ b/doc/gmp.texi Tue Apr 19 20:06:00 2022 +0200
@@ -6919,7 +6919,7 @@
@deftypefun {} mpz_class::mpz_class (type @var{n})
Construct an @code{mpz_class}. All the standard C++ types may be used, except
-@code{long long} and @code{long double}, and all the GMP C++ classes can be
+@code{long long} (in C++98) and @code{long double}, and all the GMP C++ classes can be
used, although conversions from @code{mpq_class} and @code{mpf_class} are
@code{explicit}. Any necessary conversion follows the corresponding C
function, for example @code{double} follows @code{mpz_set_d}
@@ -7026,7 +7026,7 @@
Construct an @code{mpq_class}. The initial value can be a single value of any
type (conversion from @code{mpf_class} is @code{explicit}), or a pair of
integers (@code{mpz_class} or standard C++ integer types) representing a
-fraction, except that @code{long long} and @code{long double} are not
+fraction, except that @code{long long} (in C++98) and @code{long double} are not
supported. For example,
@example
@@ -7124,7 +7124,7 @@
@deftypefun {} mpf_class::mpf_class (type @var{op})
@deftypefunx {} mpf_class::mpf_class (type @var{op}, mp_bitcnt_t @var{prec})
Construct an @code{mpf_class}. Any standard C++ type can be used, except
-@code{long long} and @code{long double}, and any of the GMP C++ classes can be
+@code{long long} (in C++98) and @code{long double}, and any of the GMP C++ classes can be
used.
If @var{prec} is given, the initial precision is that value, in bits. If
diff -r 88e4445a72d1 gmpxx.h
--- a/gmpxx.h Mon Apr 18 16:19:20 2022 +0200
+++ b/gmpxx.h Tue Apr 19 20:06:00 2022 +0200
@@ -106,6 +106,23 @@
// Note: we know the high bit of l is 0 so we could do slightly better
}
+#if __GMPXX_USE_CXX11
+inline void __mpz_set_ull_safe(mpz_ptr z, unsigned long long l)
+{
+# if ULONG_MAX == ULLONG_MAX
+ __mpz_set_ui_safe(z, static_cast<unsigned long>(l));
+# else
+ mp_limb_t *p = z->_mp_d;
+ while (l != 0)
+ {
+ *p++ = static_cast<mp_limb_t>(l & GMP_NUMB_MASK);
+ l >>= GMP_NUMB_BITS;
+ }
+ z->_mp_size = p - z->_mp_d;
+# endif
+}
+#endif
+
// Fake temporary variables
#define __GMPXX_TMPZ_UI \
mpz_t temp; \
@@ -154,6 +171,13 @@
return l >= 0 ? static_cast<unsigned long>(l)
: -static_cast<unsigned long>(l);
}
+#if __GMPXX_USE_CXX11
+inline unsigned long long __gmpxx_abs_ull (signed long long l)
+{
+ return l >= 0 ? static_cast<unsigned long long>(l)
+ : -static_cast<unsigned long long>(l);
+}
+#endif
/**************** Function objects ****************/
/* Any evaluation of a __gmp_expr ends up calling one of these functions
@@ -1511,6 +1535,35 @@
inline __gmp_expr & fun(); \
inline __gmp_expr fun(int);
+#if __GMPXX_USE_CXX11
+#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(signed long long l) { init_sll(l); } \
+ __gmp_expr(unsigned long long l) { init_ull(l); } \
+ __gmp_expr(float f) { init_d(f); } \
+ __gmp_expr(double d) { init_d(d); }
+
+#define __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS \
+ __gmp_expr & operator=(signed char c) { assign_si(c); return *this; } \
+ __gmp_expr & operator=(unsigned char c) { assign_ui(c); return *this; } \
+ __gmp_expr & operator=(signed int i) { assign_si(i); return *this; } \
+ __gmp_expr & operator=(unsigned int i) { assign_ui(i); return *this; } \
+ __gmp_expr & operator=(signed short int s) { assign_si(s); return *this; } \
+ __gmp_expr & operator=(unsigned short int s) { assign_ui(s); return *this; } \
+ __gmp_expr & operator=(signed long int l) { assign_si(l); return *this; } \
+ __gmp_expr & operator=(unsigned long int l) { assign_ui(l); return *this; } \
+ __gmp_expr & operator=(signed long long l) { assign_sll(l); return *this; } \
+ __gmp_expr & operator=(unsigned long long l) { assign_ull(l); return *this; } \
+ __gmp_expr & operator=(float f) { assign_d(f); return *this; } \
+ __gmp_expr & operator=(double d) { assign_d(d); return *this; }
+#else
#define __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS \
__gmp_expr(signed char c) { init_si(c); } \
__gmp_expr(unsigned char c) { init_ui(c); } \
@@ -1534,6 +1587,7 @@
__gmp_expr & operator=(unsigned long int l) { assign_ui(l); return *this; } \
__gmp_expr & operator=(float f) { assign_d(f); return *this; } \
__gmp_expr & operator=(double d) { assign_d(d); return *this; }
+#endif
#define __GMPP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun) \
template <class U> \
@@ -1596,6 +1650,25 @@
else
mpz_set_si(mp, l);
}
+#if __GMPXX_USE_CXX11
+ void assign_ull(unsigned long long l)
+ {
+ if (l <= ULONG_MAX)
+ {
+ assign_ui(static_cast<unsigned long>(l));
+ return;
+ }
+ if (__get_mp()->_mp_alloc * GMP_NUMB_BITS < std::numeric_limits<unsigned long long>::digits)
+ mpz_realloc2(mp, std::numeric_limits<unsigned long long>::digits);
+ __mpz_set_ull_safe(mp, l);
+ }
+ void assign_sll(signed long long l)
+ {
+ assign_ull(__gmpxx_abs_ull(l));
+ if (l < 0)
+ mpz_neg(mp, mp);
+ }
+#endif
void assign_d (double d)
{
mpz_set_d (mp, d);
@@ -1620,6 +1693,24 @@
else
mpz_init_set_si(mp, l);
}
+#if __GMPXX_USE_CXX11
+ void init_ull(unsigned long long l)
+ {
+ if (l <= ULONG_MAX)
+ {
+ init_ui(static_cast<unsigned long>(l));
+ return;
+ }
+ mpz_init2(mp, std::numeric_limits<unsigned long long>::digits);
+ __mpz_set_ull_safe(mp, l);
+ }
+ void init_sll(signed long long l)
+ {
+ init_ull(__gmpxx_abs_ull(l));
+ if (l < 0)
+ mpz_neg(mp, mp);
+ }
+#endif
void init_d (double d)
{
mpz_init_set_d (mp, d);
@@ -1767,7 +1858,7 @@
value_type mp;
// Helper functions used for all arithmetic types
- void assign_ui(unsigned long l) { mpq_set_ui(mp, l, 1); }
+ void assign_ui(unsigned long l) { mpq_set_ui(mp, l, 1); }
void assign_si(signed long l)
{
if (__GMPXX_CONSTANT_TRUE(l >= 0))
@@ -1775,11 +1866,19 @@
else
mpq_set_si(mp, l, 1);
}
- void assign_d (double d) { mpq_set_d (mp, d); }
-
- void init_ui(unsigned long l) { mpq_init(mp); get_num() = l; }
- void init_si(signed long l) { mpq_init(mp); get_num() = l; }
- void init_d (double d) { mpq_init(mp); assign_d (d); }
+#if __GMPXX_USE_CXX11
+ void assign_ull(unsigned long long l) { get_num() = l; get_den() = 1; }
+ void assign_sll(signed long long l) { get_num() = l; get_den() = 1; }
+#endif
+ void assign_d (double d) { mpq_set_d (mp, d); }
+
+ void init_ui(unsigned long l) { mpq_init(mp); get_num() = l; }
+ void init_si(signed long l) { mpq_init(mp); get_num() = l; }
+#if __GMPXX_USE_CXX11
+ void init_ull(unsigned long long l) { mpq_init(mp); get_num() = l; }
+ void init_sll(signed long long l) { mpq_init(mp); get_num() = l; }
+#endif
+ void init_d (double d) { mpq_init(mp); assign_d (d); }
public:
mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
@@ -1953,7 +2052,7 @@
value_type mp;
// Helper functions used for all arithmetic types
- void assign_ui(unsigned long l) { mpf_set_ui(mp, l); }
+ void assign_ui(unsigned long l) { mpf_set_ui(mp, l); }
void assign_si(signed long l)
{
if (__GMPXX_CONSTANT_TRUE(l >= 0))
@@ -1961,7 +2060,11 @@
else
mpf_set_si(mp, l);
}
- void assign_d (double d) { mpf_set_d (mp, d); }
+#if __GMPXX_USE_CXX11
+ void assign_sll(signed long long l) { *this = mpz_class(l); }
+ void assign_ull(unsigned long long l) { *this = mpz_class(l); }
+#endif
+ void assign_d (double d) { mpf_set_d (mp, d); }
void init_ui(unsigned long l)
{
@@ -1977,6 +2080,10 @@
else
mpf_init_set_si(mp, l);
}
+#if __GMPXX_USE_CXX11
+ void init_ull(unsigned long long l) { mpf_init(mp); assign_ull(l); }
+ void init_sll(signed long long l) { mpf_init(mp); assign_sll(l); }
+#endif
void init_d (double d) { mpf_init_set_d (mp, d); }
public:
@@ -2025,6 +2132,13 @@
__gmp_expr(unsigned long int l, mp_bitcnt_t prec)
{ mpf_init2(mp, prec); mpf_set_ui(mp, l); }
+#if __GMPXX_USE_CXX11
+ __gmp_expr(signed long long l, mp_bitcnt_t prec)
+ { mpf_init2(mp, prec); *this = mpz_class(l); }
+ __gmp_expr(unsigned long long l, mp_bitcnt_t prec)
+ { mpf_init2(mp, prec); *this = mpz_class(l); }
+#endif
+
__gmp_expr(float f, mp_bitcnt_t prec)
{ mpf_init2(mp, prec); mpf_set_d(mp, f); }
__gmp_expr(double d, mp_bitcnt_t prec)
diff -r 88e4445a72d1 tests/cxx/t-assign.cc
--- a/tests/cxx/t-assign.cc Mon Apr 18 16:19:20 2022 +0200
+++ b/tests/cxx/t-assign.cc Tue Apr 19 20:06:00 2022 +0200
@@ -118,6 +118,22 @@
b = a; ASSERT_ALWAYS(b == 3456789012UL);
}
+#if __GMPXX_USE_CXX11
+ // operator=(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpz_class b;
+ b = a; // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // operator=(unsigned long long)
+ {
+ unsigned long long a = 345678901234ULL;
+ mpz_class b;
+ b = a; // ASSERT_ALWAYS(b == 345678901234ULL);
+ }
+#endif
+
// operator=(float)
{
float a = 123.0;
@@ -304,6 +320,22 @@
b = a; ASSERT_ALWAYS(b == 3456789012UL);
}
+#if __GMPXX_USE_CXX11
+ // operator=(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpq_class b;
+ b = a; // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // operator=(unsigned long long)
+ {
+ unsigned long long a = 345678901234ULL;
+ mpq_class b;
+ b = a; // ASSERT_ALWAYS(b == 345678901234ULL);
+ }
+#endif
+
// operator=(float)
{
float a = 123.0;
@@ -490,6 +522,22 @@
b = a; ASSERT_ALWAYS(b == 3456789012UL);
}
+#if __GMPXX_USE_CXX11
+ // operator=(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpf_class b;
+ b = a; // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // operator=(unsigned long long)
+ {
+ unsigned long long a = 345678901234ULL;
+ mpf_class b;
+ b = a; // ASSERT_ALWAYS(b == 345678901234ULL);
+ }
+#endif
+
// operator=(float)
{
float a = 123.0;
diff -r 88e4445a72d1 tests/cxx/t-constr.cc
--- a/tests/cxx/t-constr.cc Mon Apr 18 16:19:20 2022 +0200
+++ b/tests/cxx/t-constr.cc Tue Apr 19 20:06:00 2022 +0200
@@ -107,6 +107,20 @@
mpz_class b(a); ASSERT_ALWAYS(b == 1073741824L);
}
+#if __GMPXX_USE_CXX11
+ // mpz_class(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpz_class b(a); // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // mpz_class(unsigned long long)
+ {
+ unsigned long long a = 1ULL << 40;
+ mpz_class b(a); // ASSERT_ALWAYS(b == 1099511627776ULL);
+ }
+#endif
+
// mpz_class(float)
{
float a = 123.45;
@@ -293,6 +307,20 @@
mpq_class b(a); ASSERT_ALWAYS(b == 1073741824L);
}
+#if __GMPXX_USE_CXX11
+ // mpq_class(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpq_class b(a); // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // mpq_class(unsigned long long)
+ {
+ unsigned long long a = 1ULL << 40;
+ mpq_class b(a); // ASSERT_ALWAYS(b == 1099511627776ULL);
+ }
+#endif
+
// mpq_class(float)
{
float a = 0.625;
@@ -555,6 +583,34 @@
mpf_class b(a, prec); ASSERT_ALWAYS(b == 3456789012UL);
}
+#if __GMPXX_USE_CXX11
+ // mpf_class(signed long long)
+ {
+ signed long long a = -123456789012LL;
+ mpf_class b(a); // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // mpf_class(unsigned long long)
+ {
+ unsigned long long a = 1ULL << 40;
+ mpf_class b(a); // ASSERT_ALWAYS(b == 1099511627776ULL);
+ }
+
+ // mpf_class(signed long long, unsigned long int)
+ {
+ signed long long a = -123456789012LL;
+ int prec = 128;
+ mpf_class b(a, prec); // ASSERT_ALWAYS(b == -123456789012LL);
+ }
+
+ // mpf_class(unsigned long long, unsigned long int)
+ {
+ unsigned long long a = 1ULL << 40;
+ int prec = 256;
+ mpf_class b(a, prec); // ASSERT_ALWAYS(b == 1099511627776ULL);
+ }
+#endif
+
// mpf_class(float)
{
float a = 1234.5;
diff -r 88e4445a72d1 tests/cxx/t-ops2z.cc
--- a/tests/cxx/t-ops2z.cc Mon Apr 18 16:19:20 2022 +0200
+++ b/tests/cxx/t-ops2z.cc Tue Apr 19 20:06:00 2022 +0200
@@ -114,6 +114,14 @@
ASSERT_ALWAYS(mpz_class::fibonacci(-3)==2);
try { ret=fibonacci(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
catch (std::bad_alloc&) {}
+#if __GMPXX_USE_CXX11
+ unsigned long long ma = (std::numeric_limits<unsigned long long>::max)();
+ signed long long mi = (std::numeric_limits< signed long long>::min)();
+ ASSERT_ALWAYS(mpz_class(ma) > mpz_class(ma-1));
+ ASSERT_ALWAYS(mpz_class(ma) > 0);
+ ASSERT_ALWAYS(mpz_class(mi) < mpz_class(mi+1));
+ ASSERT_ALWAYS(mpz_class(mi) < 0);
+#endif
}
int
_______________________________________________
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel