1 /* mpfr-mini-gmp.c -- Interface functions for mini-gmp. 2 3 Copyright 2014-2023 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramba projects, INRIA. 5 6 This file is part of the GNU MPFR Library. 7 8 The GNU MPFR Library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or (at your 11 option) any later version. 12 13 The GNU MPFR Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ 22 23 /* The following include will do 2 things: include the config.h 24 if there is one (as it may define MPFR_USE_MINI_GMP), and avoid 25 an empty translation unit (see ISO C99, 6.9). */ 26 #include "mpfr-impl.h" 27 28 #ifdef MPFR_USE_MINI_GMP 29 30 /************************ random generation functions ************************/ 31 32 #ifdef WANT_gmp_randinit_default 33 void 34 gmp_randinit_default (gmp_randstate_t state) 35 { 36 } 37 #endif 38 39 #ifdef WANT_gmp_randseed_ui 40 void 41 gmp_randseed_ui (gmp_randstate_t state, unsigned long int seed) 42 { 43 /* Note: We possibly ignore the high-order bits of seed. One should take 44 that into account when setting GMP_CHECK_RANDOMIZE for the tests. */ 45 srand ((unsigned int) seed); 46 } 47 #endif 48 49 #ifdef WANT_gmp_randclear 50 void 51 gmp_randclear (gmp_randstate_t state) 52 { 53 } 54 #endif 55 56 #ifdef WANT_gmp_randinit_set 57 void 58 gmp_randinit_set (gmp_randstate_t s1, gmp_randstate_t s2) 59 { 60 } 61 #endif 62 63 static unsigned int 64 rand15 (void) 65 { 66 /* With a good PRNG, we could use "rand () % 32768", but let's choose 67 the following from <https://c-faq.com/lib/randrange.html>. Note that 68 on most platforms, the compiler should generate a shift. */ 69 return rand () / (RAND_MAX / 32768 + 1); 70 } 71 72 static mp_limb_t 73 random_limb (void) 74 { 75 mp_limb_t r = 0; 76 int i = GMP_NUMB_BITS; 77 78 while (i > 0) 79 { 80 r = (r << 15) | rand15 (); 81 i -= 15; 82 } 83 84 return r; 85 } 86 87 #ifdef WANT_mpz_urandomb 88 void 89 mpz_urandomb (mpz_t rop, gmp_randstate_t state, mp_bitcnt_t nbits) 90 { 91 unsigned long n, i; 92 93 mpz_realloc2 (rop, nbits); 94 n = (nbits - 1) / GMP_NUMB_BITS + 1; /* number of limbs */ 95 for (i = n; i-- > 0;) 96 rop->_mp_d[i] = random_limb (); 97 i = n * GMP_NUMB_BITS - nbits; 98 /* mask the upper i bits */ 99 if (i) 100 rop->_mp_d[n-1] = MPFR_LIMB_LSHIFT(rop->_mp_d[n-1], i) >> i; 101 while (n > 0 && (rop->_mp_d[n-1] == 0)) 102 n--; 103 rop->_mp_size = n; 104 } 105 #endif 106 107 #ifdef WANT_gmp_urandomm_ui 108 /* generates a random unsigned long */ 109 static unsigned long 110 random_ulong (void) 111 { 112 #ifdef MPFR_LONG_WITHIN_LIMB 113 /* we assume a limb and an unsigned long have both a number of different 114 values that is a power of two, thus when we cast a random limb into 115 an unsigned long, we still get an uniform distribution */ 116 return random_limb (); 117 #else 118 /* with the same assumption as above, we need to generate as many random 119 limbs needed to "fill" an unsigned long */ 120 unsigned long u, v; 121 122 v = MPFR_LIMB_MAX; 123 u = random_limb (); 124 while (v < ULONG_MAX) 125 { 126 v = (v << GMP_NUMB_BITS) + MPFR_LIMB_MAX; 127 u = (u << GMP_NUMB_BITS) + random_limb (); 128 } 129 return u; 130 #endif 131 } 132 133 unsigned long 134 gmp_urandomm_ui (gmp_randstate_t state, unsigned long n) 135 { 136 unsigned long p, q, r; 137 138 MPFR_ASSERTN (n > 0); 139 p = random_ulong (); /* p is in [0, ULONG_MAX], thus p is uniform among 140 ULONG_MAX+1 values */ 141 q = n * (ULONG_MAX / n); 142 r = ULONG_MAX % n; 143 if (r != n - 1) /* ULONG_MAX+1 is not multiple of n, will happen whenever 144 n is not a power of two */ 145 while (p >= q) 146 p = random_ulong (); 147 return p % n; 148 } 149 #endif 150 151 #ifdef WANT_gmp_urandomb_ui 152 unsigned long 153 gmp_urandomb_ui (gmp_randstate_t state, unsigned long n) 154 { 155 #ifdef MPFR_LONG_WITHIN_LIMB 156 /* Since n may be equal to the width of unsigned long, 157 we must not shift 1UL by n as this may be UB. */ 158 return n == 0 ? 0 : random_limb () & (((1UL << (n - 1)) << 1) - 1); 159 #else 160 unsigned long res = 0; 161 int m = n; /* remaining bits to generate */ 162 while (m >= GMP_NUMB_BITS) 163 { 164 /* we can generate a full limb */ 165 res = (res << GMP_NUMB_BITS) | (unsigned long) random_limb (); 166 m -= GMP_NUMB_BITS; 167 } 168 MPFR_ASSERTD (m < GMP_NUMB_BITS); /* thus m < width(unsigned long) */ 169 if (m != 0) /* generate m extra bits */ 170 res = (res << m) | (unsigned long) (random_limb () % (1UL << m)); 171 return res; 172 #endif 173 } 174 #endif 175 176 /************************* division functions ********************************/ 177 178 #ifdef WANT_mpn_divrem_1 179 mp_limb_t 180 mpn_divrem_1 (mp_limb_t *qp, mp_size_t qxn, mp_limb_t *np, mp_size_t nn, 181 mp_limb_t d0) 182 { 183 mpz_t q, r, n, d; 184 mp_limb_t ret, dd[1]; 185 186 d->_mp_d = dd; 187 d->_mp_d[0] = d0; 188 d->_mp_size = 1; 189 mpz_init (q); 190 mpz_init (r); 191 if (qxn == 0) 192 { 193 n->_mp_d = np; 194 n->_mp_size = nn; 195 } 196 else 197 { 198 mpz_init2 (n, (nn + qxn) * GMP_NUMB_BITS); 199 mpn_copyi (n->_mp_d + qxn, np, nn); 200 mpn_zero (n->_mp_d, qxn); 201 n->_mp_size = nn + qxn; 202 } 203 mpz_tdiv_qr (q, r, n, d); 204 if (q->_mp_size > 0) 205 mpn_copyi (qp, q->_mp_d, q->_mp_size); 206 if (q->_mp_size < nn + qxn) 207 mpn_zero (qp + q->_mp_size, nn + qxn - q->_mp_size); 208 ret = (r->_mp_size == 1) ? r->_mp_d[0] : 0; 209 mpz_clear (q); 210 mpz_clear (r); 211 if (qxn != 0) 212 mpz_clear (n); 213 return ret; 214 } 215 #endif 216 217 #ifdef WANT_mpn_divrem 218 mp_limb_t 219 mpn_divrem (mp_limb_t *qp, mp_size_t qn, mp_limb_t *np, 220 mp_size_t nn, const mp_limb_t *dp, mp_size_t dn) 221 { 222 mpz_t q, r, n, d; 223 mp_limb_t ret; 224 225 MPFR_ASSERTN(qn == 0); 226 qn = nn - dn; 227 n->_mp_d = np; 228 n->_mp_size = nn; 229 d->_mp_d = (mp_limb_t*) dp; 230 d->_mp_size = dn; 231 mpz_init (q); 232 mpz_init (r); 233 mpz_tdiv_qr (q, r, n, d); 234 MPFR_ASSERTN(q->_mp_size == qn || q->_mp_size == qn + 1); 235 mpn_copyi (qp, q->_mp_d, qn); 236 ret = (q->_mp_size == qn) ? 0 : q->_mp_d[qn]; 237 if (r->_mp_size > 0) 238 mpn_copyi (np, r->_mp_d, r->_mp_size); 239 if (r->_mp_size < dn) 240 mpn_zero (np + r->_mp_size, dn - r->_mp_size); 241 mpz_clear (q); 242 mpz_clear (r); 243 return ret; 244 } 245 #endif 246 247 #ifdef WANT_mpn_tdiv_qr 248 void 249 mpn_tdiv_qr (mp_limb_t *qp, mp_limb_t *rp, mp_size_t qxn, 250 const mp_limb_t *np, mp_size_t nn, 251 const mp_limb_t *dp, mp_size_t dn) 252 { 253 mpz_t q, r, n, d; 254 255 MPFR_ASSERTN(qxn == 0); 256 n->_mp_d = (mp_limb_t*) np; 257 n->_mp_size = nn; 258 d->_mp_d = (mp_limb_t*) dp; 259 d->_mp_size = dn; 260 mpz_init (q); 261 mpz_init (r); 262 mpz_tdiv_qr (q, r, n, d); 263 MPFR_ASSERTN(q->_mp_size > 0); 264 mpn_copyi (qp, q->_mp_d, q->_mp_size); 265 if (q->_mp_size < nn - dn + 1) 266 mpn_zero (qp + q->_mp_size, nn - dn + 1 - q->_mp_size); 267 if (r->_mp_size > 0) 268 mpn_copyi (rp, r->_mp_d, r->_mp_size); 269 if (r->_mp_size < dn) 270 mpn_zero (rp + r->_mp_size, dn - r->_mp_size); 271 mpz_clear (q); 272 mpz_clear (r); 273 } 274 #endif 275 276 #if 0 /* this function is useful for debugging, thus please keep it here */ 277 void 278 mpz_dump (mpz_t z) 279 { 280 mp_size_t n = z->_mp_size; 281 282 MPFR_STAT_STATIC_ASSERT ((GMP_NUMB_BITS % 4) == 0); 283 284 if (n == 0) 285 printf ("0"); 286 else 287 { 288 int first = 1; 289 if (n < 0) 290 { 291 printf ("-"); 292 n = -n; 293 } 294 while (n > 0) 295 { 296 if (first) 297 { 298 printf ("%lx", (unsigned long) z->_mp_d[n-1]); 299 first = 0; 300 } 301 else 302 { 303 char s[17]; 304 int len; 305 sprintf (s, "%lx", (unsigned long) z->_mp_d[n-1]); 306 len = strlen (s); 307 /* one character should be printed for 4 bits */ 308 while (len++ < GMP_NUMB_BITS / 4) 309 printf ("0"); 310 printf ("%lx", (unsigned long) z->_mp_d[n-1]); 311 } 312 n--; 313 } 314 } 315 printf ("\n"); 316 } 317 #endif 318 319 #endif /* MPFR_USE_MINI_GMP */ 320