/* Exercise values 2^n+1, while such a value fits the mantissa of a double. */ void check_twobit (void) { int i, mant_bits; double got, want; mp_size_t nsize, sign; mp_ptr np; mant_bits = tests_dbl_mant_bits (); if (mant_bits == 0) return; np = refmpn_malloc_limbs (BITS_TO_LIMBS (mant_bits)); want = 3.0; for (i = 1; i < mant_bits; i++) { nsize = BITS_TO_LIMBS (i+1); refmpn_zero (np, nsize); np[i/GMP_NUMB_BITS] = CNST_LIMB(1) << (i % GMP_NUMB_BITS); np[0] |= 1; for (sign = 0; sign >= -1; sign--) { got = mpn_get_d (np, nsize, sign, 0); if (got != want) { printf ("mpn_get_d wrong on 2^%d + 1\n", i); printf (" sign %ld\n", (long) sign); mpn_trace (" n ", np, nsize); printf (" nsize %ld\n", (long) nsize); d_trace (" want ", want); d_trace (" got ", got); abort(); } want = -want; } want = 2.0 * want - 1.0; } free (np); }
/* c is the top bits of the inputs, (fully reduced) c & 2 is the top bit of y c & 1 is the top bit of z */ int mpn_mulmod_2expp1_basecase (mp_ptr xp, mp_srcptr yp, mp_srcptr zp, int c, mpir_ui b, mp_ptr tp) { int cy, cz; mp_size_t n, k; cy = c & 2; cz = c & 1; n = BITS_TO_LIMBS (b); k = GMP_NUMB_BITS * n - b; ASSERT(b > 0); ASSERT(n > 0); ASSERT_MPN(yp, n); ASSERT_MPN(zp, n); ASSERT(!MPN_OVERLAP_P (tp, 2 * n, yp, n)); ASSERT(!MPN_OVERLAP_P (tp, 2 * n, zp, n)); ASSERT(MPN_SAME_OR_SEPARATE_P (xp, tp, n)); ASSERT(MPN_SAME_OR_SEPARATE_P (xp, tp + n, n)); ASSERT(k == 0 || yp[n - 1] >> (GMP_NUMB_BITS - k) == 0); ASSERT(k == 0 || zp[n - 1] >> (GMP_NUMB_BITS - k) == 0); #if WANT_ASSERT { mp_size_t t = n; MPN_NORMALIZE(yp, t); ASSERT(cy == 0 || t == 0); t = n; MPN_NORMALIZE(zp, t); ASSERT(cz == 0 || t == 0); } #endif if (LIKELY (cy == 0)) { if (LIKELY (cz == 0)) { c = mpn_mulmod_2expp1_internal (xp, yp, zp, b, tp); } else { c = mpn_neg_n (xp, yp, n); c = mpn_add_1 (xp, xp, n, c); xp[n - 1] &= GMP_NUMB_MASK >> k; } } else { if (LIKELY (cz == 0))
void mpz_urandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long int nbits) { mp_ptr rp; mp_size_t size; size = BITS_TO_LIMBS (nbits); rp = MPZ_REALLOC (rop, size); _gmp_rand (rp, rstate, nbits); MPN_NORMALIZE (rp, size); SIZ (rop) = size; }
static void randseed_lc (gmp_randstate_t rstate, mpz_srcptr seed) { gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate); mpz_ptr seedz = p->_mp_seed; mp_size_t seedn = BITS_TO_LIMBS (p->_mp_m2exp); /* Store p->_mp_seed as an unnormalized integer with size enough for numbers up to 2^m2exp-1. That size can't be zero. */ mpz_fdiv_r_2exp (seedz, seed, p->_mp_m2exp); MPN_ZERO (&PTR (seedz)[SIZ (seedz)], seedn - SIZ (seedz)); SIZ (seedz) = seedn; }
void mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, mp_bitcnt_t nbits) { mp_size_t nl; mp_ptr xp; nl = BITS_TO_LIMBS (nbits); if (nbits != 0) { xp = MPZ_NEWALLOC (x, nl); gmp_rrandomb (xp, rstate, nbits); } SIZ(x) = nl; }
void gmp_randinit_lc_2exp (gmp_randstate_t rstate, mpz_srcptr a, unsigned long int c, mp_bitcnt_t m2exp) { gmp_rand_lc_struct *p; mp_size_t seedn = BITS_TO_LIMBS (m2exp); ASSERT_ALWAYS (m2exp != 0); p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct); RNG_STATE (rstate) = (void *) p; RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator; /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */ mpz_init2 (p->_mp_seed, m2exp); MPN_ZERO (PTR (p->_mp_seed), seedn); SIZ (p->_mp_seed) = seedn; PTR (p->_mp_seed)[0] = 1; /* "a", forced to 0 to 2^m2exp-1 */ mpz_init (p->_mp_a); mpz_fdiv_r_2exp (p->_mp_a, a, m2exp); /* Avoid SIZ(a) == 0 to avoid checking for special case in lc(). */ if (SIZ (p->_mp_a) == 0) { SIZ (p->_mp_a) = 1; PTR (p->_mp_a)[0] = CNST_LIMB (0); } MPN_SET_UI (p->_cp, p->_cn, c); /* Internally we may discard any bits of c above m2exp. The following code ensures that __GMPN_ADD in lc() will always work. */ if (seedn < p->_cn) p->_cn = (p->_cp[0] != 0); p->_mp_m2exp = m2exp; }
static void gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, mp_bitcnt_t nbits) { mp_bitcnt_t bi; mp_limb_t ranm; /* buffer for random bits */ unsigned cap_chunksize, chunksize; mp_size_t i; /* Set entire result to 111..1 */ i = BITS_TO_LIMBS (nbits) - 1; rp[i] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - (nbits % GMP_NUMB_BITS)) % GMP_NUMB_BITS; for (i = i - 1; i >= 0; i--) rp[i] = GMP_NUMB_MAX; _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); cap_chunksize = nbits / (ranm % 4 + 1); cap_chunksize += cap_chunksize == 0; /* make it at least 1 */ bi = nbits; for (;;) { _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); chunksize = 1 + ranm % cap_chunksize; bi = (bi < chunksize) ? 0 : bi - chunksize; if (bi == 0) break; /* low chunk is ...1 */ rp[bi / GMP_NUMB_BITS] ^= CNST_LIMB (1) << bi % GMP_NUMB_BITS; _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); chunksize = 1 + ranm % cap_chunksize; bi = (bi < chunksize) ? 0 : bi - chunksize; mpn_incr_u (rp + bi / GMP_NUMB_BITS, CNST_LIMB (1) << bi % GMP_NUMB_BITS); if (bi == 0) break; /* low chunk is ...0 */ } }
/* ret + (xp, n) = (yp, n)*(zp, n) % 2^b + 1 needs (tp, 2n) temp space, everything reduced mod 2^b inputs, outputs are fully reduced N.B: 2n is not the same as 2b rounded up to nearest limb! */ inline static int mpn_mulmod_2expp1_internal (mp_ptr xp, mp_srcptr yp, mp_srcptr zp, mpir_ui b, mp_ptr tp) { mp_size_t n, k; mp_limb_t c; TMP_DECL; n = BITS_TO_LIMBS (b); k = GMP_NUMB_BITS * n - b; ASSERT(b > 0); ASSERT(n > 0); ASSERT_MPN(yp, n); ASSERT_MPN(zp, n); ASSERT(!MPN_OVERLAP_P (tp, 2 * n, yp, n)); ASSERT(!MPN_OVERLAP_P (tp, 2 * n, zp, n)); ASSERT(MPN_SAME_OR_SEPARATE_P (xp, tp, n)); ASSERT(MPN_SAME_OR_SEPARATE_P (xp, tp + n, n)); ASSERT(k == 0 || yp[n - 1] >> (GMP_NUMB_BITS - k) == 0); ASSERT(k == 0 || zp[n - 1] >> (GMP_NUMB_BITS - k) == 0); #ifndef TUNE_PROGRAM_BUILD if (k == 0 && n > FFT_MULMOD_2EXPP1_CUTOFF && n == mpir_fft_adjust_limbs(n)) { mp_bitcnt_t depth1, depth = 1; mp_size_t w1, off; mp_ptr tx, ty, tz; mp_limb_t ret; TMP_MARK; tx = TMP_BALLOC_LIMBS(3*n + 3); ty = tx + n + 1; tz = ty + n + 1; MPN_COPY(ty, yp, n); MPN_COPY(tz, zp, n); ty[n] = 0; tz[n] = 0; while ((((mp_limb_t)1)<<depth) < b) depth++; if (depth < 12) off = mulmod_2expp1_table_n[0]; else off = mulmod_2expp1_table_n[MIN(depth, FFT_N_NUM + 11) - 12]; depth1 = depth/2 - off; w1 = b/(((mp_limb_t)1)<<(2*depth1)); mpir_fft_mulmod_2expp1(tx, ty, tz, n, depth1, w1); MPN_COPY(xp, tx, n); ret = tx[n]; TMP_FREE; return ret; } #endif if (yp == zp) mpn_sqr(tp, yp, n); else mpn_mul_n (tp, yp, zp, n); if (k == 0) { c = mpn_sub_n (xp, tp, tp + n, n); return mpn_add_1 (xp, xp, n, c); } c = tp[n - 1]; tp[n - 1] &= GMP_NUMB_MASK >> k; #if HAVE_NATIVE_mpn_sublsh_nc c = mpn_sublsh_nc (xp, tp, tp + n, n, k, c); #else { mp_limb_t c1; c1 = mpn_lshift (tp + n, tp + n, n, k); tp[n] |= c >> (GMP_NUMB_BITS - k); c = mpn_sub_n (xp, tp, tp + n, n) + c1; } #endif c = mpn_add_1 (xp, xp, n, c); xp[n - 1] &= GMP_NUMB_MASK >> k; return c; }
static unsigned long int lc (mp_ptr rp, gmp_randstate_t rstate) { mp_ptr tp, seedp, ap; mp_size_t ta; mp_size_t tn, seedn, an; unsigned long int m2exp; unsigned long int bits; int cy; mp_size_t xn; gmp_rand_lc_struct *p; TMP_DECL; p = (gmp_rand_lc_struct *) RNG_STATE (rstate); m2exp = p->_mp_m2exp; seedp = PTR (p->_mp_seed); seedn = SIZ (p->_mp_seed); ap = PTR (p->_mp_a); an = SIZ (p->_mp_a); /* Allocate temporary storage. Let there be room for calculation of (A * seed + C) % M, or M if bigger than that. */ TMP_MARK; ta = an + seedn + 1; tn = BITS_TO_LIMBS (m2exp); if (ta <= tn) /* that is, if (ta < tn + 1) */ { mp_size_t tmp = an + seedn; ta = tn + 1; tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out. */ } else tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); /* t = a * seed. NOTE: an is always > 0; see initialization. */ ASSERT (seedn >= an && an > 0); mpn_mul (tp, seedp, seedn, ap, an); /* t = t + c. NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD); see initialization. */ ASSERT (tn >= p->_cn); __GMPN_ADD (cy, tp, tp, tn, p->_cp, p->_cn); /* t = t % m */ tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1; /* Save result as next seed. */ MPN_COPY (PTR (p->_mp_seed), tp, tn); /* Discard the lower m2exp/2 of the result. */ bits = m2exp / 2; xn = bits / GMP_NUMB_BITS; tn -= xn; if (tn > 0) { unsigned int cnt = bits % GMP_NUMB_BITS; if (cnt != 0) { mpn_rshift (tp, tp + xn, tn, cnt); MPN_COPY_INCR (rp, tp, xn + 1); } else /* Even limb boundary. */ MPN_COPY_INCR (rp, tp + xn, tn); } TMP_FREE; /* Return number of valid bits in the result. */ return (m2exp + 1) / 2; }
/* Obtain a sequence of random numbers. */ static void randget_lc (gmp_randstate_t rstate, mp_ptr rp, unsigned long int nbits) { unsigned long int rbitpos; int chunk_nbits; mp_ptr tp; mp_size_t tn; gmp_rand_lc_struct *p; TMP_DECL; p = (gmp_rand_lc_struct *) RNG_STATE (rstate); TMP_MARK; chunk_nbits = p->_mp_m2exp / 2; tn = BITS_TO_LIMBS (chunk_nbits); tp = (mp_ptr) TMP_ALLOC (tn * BYTES_PER_MP_LIMB); rbitpos = 0; while (rbitpos + chunk_nbits <= nbits) { mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS; if (rbitpos % GMP_NUMB_BITS != 0) { mp_limb_t savelimb, rcy; /* Target of new chunk is not bit aligned. Use temp space and align things by shifting it up. */ lc (tp, rstate); savelimb = r2p[0]; rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS); r2p[0] |= savelimb; /* bogus */ if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS) > GMP_NUMB_BITS) r2p[tn] = rcy; } else { /* Target of new chunk is bit aligned. Let `lc' put bits directly into our target variable. */ lc (r2p, rstate); } rbitpos += chunk_nbits; } /* Handle last [0..chunk_nbits) bits. */ if (rbitpos != nbits) { mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS; int last_nbits = nbits - rbitpos; tn = BITS_TO_LIMBS (last_nbits); lc (tp, rstate); if (rbitpos % GMP_NUMB_BITS != 0) { mp_limb_t savelimb, rcy; /* Target of new chunk is not bit aligned. Use temp space and align things by shifting it up. */ savelimb = r2p[0]; rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS); r2p[0] |= savelimb; if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits) r2p[tn] = rcy; } else { MPN_COPY (r2p, tp, tn); } /* Mask off top bits if needed. */ if (nbits % GMP_NUMB_BITS != 0) rp[nbits / GMP_NUMB_BITS] &= ~(~CNST_LIMB (0) << nbits % GMP_NUMB_BITS); } TMP_FREE; }
/* Exercise various 2^n values, with various exponents and positive and negative. */ void check_onebit (void) { static const int bit_table[] = { 0, 1, 2, 3, GMP_NUMB_BITS - 2, GMP_NUMB_BITS - 1, GMP_NUMB_BITS, GMP_NUMB_BITS + 1, GMP_NUMB_BITS + 2, 2 * GMP_NUMB_BITS - 2, 2 * GMP_NUMB_BITS - 1, 2 * GMP_NUMB_BITS, 2 * GMP_NUMB_BITS + 1, 2 * GMP_NUMB_BITS + 2, 3 * GMP_NUMB_BITS - 2, 3 * GMP_NUMB_BITS - 1, 3 * GMP_NUMB_BITS, 3 * GMP_NUMB_BITS + 1, 3 * GMP_NUMB_BITS + 2, 4 * GMP_NUMB_BITS - 2, 4 * GMP_NUMB_BITS - 1, 4 * GMP_NUMB_BITS, 4 * GMP_NUMB_BITS + 1, 4 * GMP_NUMB_BITS + 2, 5 * GMP_NUMB_BITS - 2, 5 * GMP_NUMB_BITS - 1, 5 * GMP_NUMB_BITS, 5 * GMP_NUMB_BITS + 1, 5 * GMP_NUMB_BITS + 2, 6 * GMP_NUMB_BITS - 2, 6 * GMP_NUMB_BITS - 1, 6 * GMP_NUMB_BITS, 6 * GMP_NUMB_BITS + 1, 6 * GMP_NUMB_BITS + 2, }; static const int exp_table[] = { 0, -100, -10, -1, 1, 10, 100, }; /* FIXME: It'd be better to base this on the float format. */ int limit = 511; int bit_i, exp_i, i; double got, want; mp_size_t nsize, sign; long bit, exp, want_bit; mp_limb_t np[20]; for (bit_i = 0; bit_i < numberof (bit_table); bit_i++) { bit = bit_table[bit_i]; nsize = BITS_TO_LIMBS (bit+1); refmpn_zero (np, nsize); np[bit/GMP_NUMB_BITS] = CNST_LIMB(1) << (bit % GMP_NUMB_BITS); for (exp_i = 0; exp_i < numberof (exp_table); exp_i++) { exp = exp_table[exp_i]; want_bit = bit + exp; if (want_bit > limit || want_bit < -limit) continue; want = 1.0; for (i = 0; i < want_bit; i++) want *= 2.0; for (i = 0; i > want_bit; i--) want *= 0.5; for (sign = 0; sign >= -1; sign--, want = -want) { got = mpn_get_d (np, nsize, sign, exp); if (got != want) { printf ("mpn_get_d wrong on 2^n\n"); printf (" bit %ld\n", bit); printf (" exp %ld\n", exp); printf (" want_bit %ld\n", want_bit); printf (" sign %ld\n", (long) sign); mpn_trace (" n ", np, nsize); printf (" nsize %ld\n", (long) nsize); d_trace (" want ", want); d_trace (" got ", got); abort(); } } } } }
void check_rand (void) { gmp_randstate_t rands; int rep, i; unsigned long mant_bits; long exp, exp_min, exp_max; double got, want, d; mp_size_t nalloc, nsize, sign; mp_limb_t nhigh_mask; mp_ptr np; gmp_randinit_default(rands); mant_bits = tests_dbl_mant_bits (); if (mant_bits == 0) return; /* Allow for vax D format with exponent 127 to -128 only. FIXME: Do something to probe for a valid exponent range. */ exp_min = -100 - mant_bits; exp_max = 100 - mant_bits; /* space for mant_bits */ nalloc = BITS_TO_LIMBS (mant_bits); np = refmpn_malloc_limbs (nalloc); nhigh_mask = MP_LIMB_T_MAX >> (GMP_NAIL_BITS + nalloc * GMP_NUMB_BITS - mant_bits); for (rep = 0; rep < 200; rep++) { /* random exp_min to exp_max, inclusive */ exp = exp_min + (long) gmp_urandomm_ui (rands, exp_max - exp_min + 1); /* mant_bits worth of random at np */ if (rep & 1) mpn_randomb (np, rands, nalloc); else mpn_rrandom (np, rands,nalloc); nsize = nalloc; np[nsize-1] &= nhigh_mask; MPN_NORMALIZE (np, nsize); if (nsize == 0) continue; sign = (mp_size_t) gmp_urandomb_ui (rands, 1L) - 1; /* want = {np,nsize}, converting one bit at a time */ want = 0.0; for (i = 0, d = 1.0; i < mant_bits; i++, d *= 2.0) if (np[i/GMP_NUMB_BITS] & (CNST_LIMB(1) << (i%GMP_NUMB_BITS))) want += d; if (sign < 0) want = -want; /* want = want * 2^exp */ for (i = 0; i < exp; i++) want *= 2.0; for (i = 0; i > exp; i--) want *= 0.5; got = mpn_get_d (np, nsize, sign, exp); if (got != want) { printf ("mpn_get_d wrong on random data\n"); printf (" sign %ld\n", (long) sign); mpn_trace (" n ", np, nsize); printf (" nsize %ld\n", (long) nsize); printf (" exp %ld\n", exp); d_trace (" want ", want); d_trace (" got ", got); abort(); } } free (np); gmp_randclear(rands); }
size_t mpz_inp_raw (mpz_ptr x, FILE *fp) { unsigned char csize_bytes[4]; mp_size_t csize, abs_xsize, i; size_t abs_csize; char *cp; mp_ptr xp, sp, ep; mp_limb_t slimb, elimb; if (fp == 0) fp = stdin; /* 4 bytes for size */ if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1) return 0; csize = ( (mp_size_t) csize_bytes[0] << 24) + ((mp_size_t) csize_bytes[1] << 16) + ((mp_size_t) csize_bytes[2] << 8) + ((mp_size_t) csize_bytes[3]); /* Sign extend if necessary. Could write "csize -= ((csize & 0x80000000L) << 1)", but that tickles a bug in gcc 3.0 for powerpc64 on AIX. */ if (sizeof (csize) > 4 && csize & 0x80000000L) csize -= 0x80000000L << 1; abs_csize = ABS (csize); /* round up to a multiple of limbs */ abs_xsize = BITS_TO_LIMBS (abs_csize*8); if (abs_xsize != 0) { xp = MPZ_NEWALLOC (x, abs_xsize); /* Get limb boundaries right in the read, for the benefit of the non-nails case. */ xp[0] = 0; cp = (char *) (xp + abs_xsize) - abs_csize; if (fread (cp, abs_csize, 1, fp) != 1) return 0; if (GMP_NAIL_BITS == 0) { /* Reverse limbs to least significant first, and byte swap. If abs_xsize is odd then on the last iteration elimb and slimb are the same. It doesn't seem extra code to handle that case separately, to save an NTOH. */ sp = xp; ep = xp + abs_xsize-1; for (i = 0; i < (abs_xsize+1)/2; i++) { NTOH_LIMB_FETCH (elimb, ep); NTOH_LIMB_FETCH (slimb, sp); *sp++ = elimb; *ep-- = slimb; } } else { /* It ought to be possible to do the transformation in-place, but for now it's easier to use an extra temporary area. */ mp_limb_t byte, limb; int bits; mp_size_t tpos; mp_ptr tp; TMP_DECL; TMP_MARK; tp = TMP_ALLOC_LIMBS (abs_xsize); limb = 0; bits = 0; tpos = 0; for (i = abs_csize-1; i >= 0; i--) { byte = (unsigned char) cp[i]; limb |= (byte << bits); bits += 8; if (bits >= GMP_NUMB_BITS) { ASSERT (tpos < abs_xsize); tp[tpos++] = limb & GMP_NUMB_MASK; bits -= GMP_NUMB_BITS; ASSERT (bits < 8); limb = byte >> (8 - bits); } } if (bits != 0) { ASSERT (tpos < abs_xsize); tp[tpos++] = limb; } ASSERT (tpos == abs_xsize); MPN_COPY (xp, tp, abs_xsize); TMP_FREE; }