version 1.1, 2000/09/09 14:12:56 |
version 1.1.1.2, 2003/08/25 16:06:33 |
|
|
long runs of consecutive ones and zeros in the binary representation. |
long runs of consecutive ones and zeros in the binary representation. |
Meant for testing of other MP routines. |
Meant for testing of other MP routines. |
|
|
Copyright (C) 2000 Free Software Foundation, Inc. |
Copyright 2000, 2001, 2002 Free Software Foundation, Inc. |
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
Line 27 MA 02111-1307, USA. */ |
|
Line 27 MA 02111-1307, USA. */ |
|
static void gmp_rrandomb _PROTO ((mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits)); |
static void gmp_rrandomb _PROTO ((mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits)); |
|
|
void |
void |
#if __STDC__ |
|
mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, unsigned long int nbits) |
mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, unsigned long int nbits) |
#else |
|
mpz_rrandomb (x, rstate, nbits) |
|
mpz_ptr x; |
|
gmp_randstate_t rstate; |
|
unsigned long int nbits; |
|
#endif |
|
{ |
{ |
mp_size_t nl = 0; |
mp_size_t nl = 0; |
|
|
if (nbits != 0) |
if (nbits != 0) |
{ |
{ |
mp_ptr xp; |
mp_ptr xp; |
nl = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; |
nl = (nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; |
if (x->_mp_alloc < nl) |
MPZ_REALLOC (x, nl); |
_mpz_realloc (x, nl); |
|
|
|
xp = PTR(x); |
xp = PTR(x); |
gmp_rrandomb (xp, rstate, nbits); |
gmp_rrandomb (xp, rstate, nbits); |
Line 53 mpz_rrandomb (x, rstate, nbits) |
|
Line 45 mpz_rrandomb (x, rstate, nbits) |
|
SIZ(x) = nl; |
SIZ(x) = nl; |
} |
} |
|
|
#define BITS_PER_CHUNK 4 |
/* It's a bit tricky to get this right, so please test the code well if you |
|
hack with it. Some early versions of the function produced random numbers |
|
with the leading limb == 0, and some versions never made the most |
|
significant bit set. |
|
|
static void |
This code and mpn_random2 are almost identical, though the latter makes bit |
#if __STDC__ |
runs of 1 to 32, and forces the first block to contain 1-bits. |
gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits) |
|
|
The random state produces some number of random bits per underlying lc |
|
invocation (BITS_PER_RANDCALL). We should perhaps ask for that, instead of |
|
asking for 32, presuming that limbs are at least 32 bits. FIXME: Handle |
|
smaller limbs, such as 4-bit limbs useful for testing purposes, or limbs |
|
truncated by nailing. |
|
|
|
For efficiency, we make sure to use most bits returned from _gmp_rand, since |
|
the underlying random number generator is slow. We keep returned bits in |
|
ranm/ran, and a count of how many bits remaining in ran_nbits. */ |
|
|
|
#define LOGBITS_PER_BLOCK 4 |
|
|
|
/* Ask _gmp_rand for 32 bits per call unless that's more than a limb can hold. |
|
Thus, we get the same random number sequence in the common cases. |
|
FIXME: We should always generate the same random number sequence! */ |
|
#if GMP_NUMB_BITS < 32 |
|
#define BITS_PER_RANDCALL GMP_NUMB_BITS |
#else |
#else |
gmp_rrandomb (rp, rstate, nbits) |
#define BITS_PER_RANDCALL 32 |
mp_ptr rp; |
|
gmp_randstate_t rstate; |
|
unsigned long int nbits; |
|
#endif |
#endif |
|
|
|
static void |
|
gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits) |
{ |
{ |
int nb; |
int nb; |
int bit_pos; |
int bit_pos; /* bit number of least significant bit where |
mp_size_t limb_pos; |
next bit field to be inserted */ |
mp_limb_t ran, ranm; |
mp_size_t ri; /* index in rp */ |
mp_limb_t acc; |
mp_limb_t ran, ranm; /* buffer for random bits */ |
mp_size_t n; |
mp_limb_t acc; /* accumulate output random data here */ |
|
int ran_nbits; /* number of valid bits in ran */ |
|
|
bit_pos = nbits % BITS_PER_MP_LIMB; |
ran_nbits = 0; |
limb_pos = nbits / BITS_PER_MP_LIMB; |
bit_pos = (nbits - 1) % GMP_NUMB_BITS; |
if (bit_pos == 0) |
ri = (nbits - 1) / GMP_NUMB_BITS; |
{ |
|
bit_pos = BITS_PER_MP_LIMB; |
|
limb_pos--; |
|
} |
|
|
|
acc = 0; |
acc = 0; |
while (limb_pos >= 0) |
while (ri >= 0) |
{ |
{ |
_gmp_rand (&ranm, rstate, BITS_PER_CHUNK + 1); |
if (ran_nbits < LOGBITS_PER_BLOCK + 1) |
ran = ranm; |
{ |
nb = (ran >> 1) + 1; |
_gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); |
|
ran = ranm; |
|
ran_nbits = BITS_PER_RANDCALL; |
|
} |
|
|
|
nb = (ran >> 1) % (1 << LOGBITS_PER_BLOCK) + 1; |
if ((ran & 1) != 0) |
if ((ran & 1) != 0) |
{ |
{ |
/* Generate a string of ones. */ |
/* Generate a string of nb ones. */ |
if (nb > bit_pos) |
if (nb > bit_pos) |
{ |
{ |
rp[limb_pos--] = acc | ((((mp_limb_t) 1) << bit_pos) - 1); |
rp[ri--] = acc | (((mp_limb_t) 2 << bit_pos) - 1); |
bit_pos += BITS_PER_MP_LIMB; |
bit_pos += GMP_NUMB_BITS; |
bit_pos -= nb; |
bit_pos -= nb; |
acc = (~(mp_limb_t) 0) << bit_pos; |
acc = ((~(mp_limb_t) 1) << bit_pos) & GMP_NUMB_MASK; |
} |
} |
else |
else |
{ |
{ |
bit_pos -= nb; |
bit_pos -= nb; |
acc |= ((((mp_limb_t) 1) << nb) - 1) << bit_pos; |
acc |= (((mp_limb_t) 2 << nb) - 2) << bit_pos; |
} |
} |
} |
} |
else |
else |
{ |
{ |
/* Generate a string of zeroes. */ |
/* Generate a string of nb zeroes. */ |
if (nb > bit_pos) |
if (nb > bit_pos) |
{ |
{ |
rp[limb_pos--] = acc; |
rp[ri--] = acc; |
acc = 0; |
acc = 0; |
bit_pos += BITS_PER_MP_LIMB; |
bit_pos += GMP_NUMB_BITS; |
} |
} |
bit_pos -= nb; |
bit_pos -= nb; |
} |
} |
|
ran_nbits -= LOGBITS_PER_BLOCK + 1; |
|
ran >>= LOGBITS_PER_BLOCK + 1; |
} |
} |
} |
} |