summaryrefslogtreecommitdiff
path: root/Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c')
-rw-r--r--Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c126
1 files changed, 115 insertions, 11 deletions
diff --git a/Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c b/Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c
index 1b2cd25315e..abdcb9aa280 100644
--- a/Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c
+++ b/Build/source/libs/mpfr/mpfr-src/src/mpfr-mini-gmp.c
@@ -1,6 +1,6 @@
/* mpfr-mini-gmp.c -- Interface functions for mini-gmp.
-Copyright 2014-2019 Free Software Foundation, Inc.
+Copyright 2014-2020 Free Software Foundation, Inc.
Contributed by the AriC and Caramba projects, INRIA.
This file is part of the GNU MPFR Library.
@@ -27,8 +27,6 @@ https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
#ifdef MPFR_USE_MINI_GMP
-#include "mpfr-mini-gmp.h"
-
/************************ random generation functions ************************/
#ifdef WANT_gmp_randinit_default
@@ -42,7 +40,9 @@ gmp_randinit_default (gmp_randstate_t state)
void
gmp_randseed_ui (gmp_randstate_t state, unsigned long int seed)
{
- srand48 (seed);
+ /* With a portable version of the conversion from unsigned long to long
+ (at least GCC and Clang optimize this expression to identity). */
+ srand48 (seed > LONG_MAX ? -1 - (long) ~seed : (long) seed);
}
#endif
@@ -63,12 +63,22 @@ gmp_randinit_set (gmp_randstate_t s1, gmp_randstate_t s2)
static mp_limb_t
random_limb (void)
{
- /* lrand48() only gives 31 bits */
-#if GMP_NUMB_BITS == 32
- return lrand48 () + (lrand48 () << 31);
+ /* lrand48() returns a random number in [0, 2^31-1],
+ but the low 15 bits do not depend on the random seed,
+ thus it is safer to use the upper bits */
+#if GMP_NUMB_BITS < 32
+ /* use the upper GMP_NUMB_BITS bits from lrand48 () */
+ return (mp_limb_t) (lrand48 () >> (31 - GMP_NUMB_BITS));
+#elif GMP_NUMB_BITS == 32
+ /* use the upper 16 bits from two lrand48 calls */
+ return (lrand48 () >> 15) + ((lrand48 () >> 15) << 16);
+#elif GMP_NUMB_BITS == 64
+ /* use the upper 16 bits from four lrand48 calls */
+ return (lrand48 () >> 15) + ((((mp_limb_t) lrand48 ()) >> 15) << 16)
+ + ((((mp_limb_t) lrand48 ()) >> 15) << 32)
+ + ((((mp_limb_t) lrand48 ()) >> 15) << 48);
#else
- return lrand48 () + (((mp_limb_t) lrand48 ()) << 31)
- + (((mp_limb_t) lrand48 ()) << 62);
+#error "GMP_NUMB_BITS should be 8, 16, 32 or >= 64"
#endif
}
@@ -85,7 +95,7 @@ mpz_urandomb (mpz_t rop, gmp_randstate_t state, mp_bitcnt_t nbits)
i = n * GMP_NUMB_BITS - nbits;
/* mask the upper i bits */
if (i)
- rop->_mp_d[n-1] = (rop->_mp_d[n-1] << i) >> i;
+ rop->_mp_d[n-1] = MPFR_LIMB_LSHIFT(rop->_mp_d[n-1], i) >> i;
while (n > 0 && (rop->_mp_d[n-1] == 0))
n--;
rop->_mp_size = n;
@@ -93,10 +103,46 @@ mpz_urandomb (mpz_t rop, gmp_randstate_t state, mp_bitcnt_t nbits)
#endif
#ifdef WANT_gmp_urandomm_ui
+/* generates a random unsigned long */
+static unsigned long
+random_ulong (void)
+{
+#ifdef MPFR_LONG_WITHIN_LIMB
+ /* we assume a limb and an unsigned long have both a number of different
+ values that is a power of two, thus when we cast a random limb into
+ an unsigned long, we still get an uniform distribution */
+ return random_limb ();
+#else
+ /* with the same assumption as above, we need to generate as many random
+ limbs needed to "fill" an unsigned long */
+ unsigned long u, v;
+
+ v = MPFR_LIMB_MAX;
+ u = random_limb ();
+ while (v < ULONG_MAX)
+ {
+ v = (v << GMP_NUMB_BITS) + MPFR_LIMB_MAX;
+ u = (u << GMP_NUMB_BITS) + random_limb ();
+ }
+ return u;
+#endif
+}
+
unsigned long
gmp_urandomm_ui (gmp_randstate_t state, unsigned long n)
{
- return random_limb () % n;
+ unsigned long p, q, r;
+
+ MPFR_ASSERTN (n > 0);
+ p = random_ulong (); /* p is in [0, ULONG_MAX], thus p is uniform among
+ ULONG_MAX+1 values */
+ q = n * (ULONG_MAX / n);
+ r = ULONG_MAX % n;
+ if (r != n - 1) /* ULONG_MAX+1 is not multiple of n, will happen whenever
+ n is not a power of two */
+ while (p >= q)
+ p = random_ulong ();
+ return p % n;
}
#endif
@@ -104,7 +150,22 @@ gmp_urandomm_ui (gmp_randstate_t state, unsigned long n)
unsigned long
gmp_urandomb_ui (gmp_randstate_t state, unsigned long n)
{
+#ifdef MPFR_LONG_WITHIN_LIMB
return random_limb () % (1UL << n);
+#else
+ unsigned long res = 0;
+ int m = n; /* remaining bits to generate */
+ while (m >= GMP_NUMB_BITS)
+ {
+ /* we can generate a full limb */
+ res = (res << GMP_NUMB_BITS) | (unsigned long) random_limb ();
+ m -= GMP_NUMB_BITS;
+ }
+ /* now m < GMP_NUMB_BITS */
+ if (m) /* generate m extra bits */
+ res = (res << m) | (unsigned long) (random_limb () % (1UL << m));
+ return res;
+#endif
}
#endif
@@ -208,4 +269,47 @@ mpn_tdiv_qr (mp_limb_t *qp, mp_limb_t *rp, mp_size_t qxn,
}
#endif
+#if 0 /* this function is useful for debugging, thus please keep it here */
+void
+mpz_dump (mpz_t z)
+{
+ mp_size_t n = z->_mp_size;
+
+ MPFR_STAT_STATIC_ASSERT ((GMP_NUMB_BITS % 4) == 0);
+
+ if (n == 0)
+ printf ("0");
+ else
+ {
+ int first = 1;
+ if (n < 0)
+ {
+ printf ("-");
+ n = -n;
+ }
+ while (n > 0)
+ {
+ if (first)
+ {
+ printf ("%lx", (unsigned long) z->_mp_d[n-1]);
+ first = 0;
+ }
+ else
+ {
+ char s[17];
+ int len;
+ sprintf (s, "%lx", (unsigned long) z->_mp_d[n-1]);
+ len = strlen (s);
+ /* one character should be printed for 4 bits */
+ while (len++ < GMP_NUMB_BITS / 4)
+ printf ("0");
+ printf ("%lx", (unsigned long) z->_mp_d[n-1]);
+ }
+ n--;
+ }
+ }
+ printf ("\n");
+}
+#endif
+
#endif /* MPFR_USE_MINI_GMP */