version 1.1.1.2, 2000/09/09 14:12:27 |
version 1.1.1.3, 2003/08/25 16:06:20 |
|
|
/* mpn_random2 -- Generate random numbers with relatively long strings |
/* mpn_random2 -- Generate random numbers with relatively long strings |
of ones and zeroes. Suitable for border testing. |
of ones and zeroes. Suitable for border testing. |
|
|
Copyright (C) 1992, 1993, 1994, 1996, 2000 Free Software Foundation, Inc. |
Copyright 1992, 1993, 1994, 1996, 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 23 MA 02111-1307, USA. */ |
|
Line 23 MA 02111-1307, USA. */ |
|
#include "gmp.h" |
#include "gmp.h" |
#include "gmp-impl.h" |
#include "gmp-impl.h" |
|
|
#if defined (__hpux) || defined (__alpha) || defined (__svr4__) || defined (__SVR4) |
|
/* HPUX lacks random(). DEC OSF/1 1.2 random() returns a double. */ |
|
long mrand48 (); |
|
static inline long |
|
random () |
|
{ |
|
return mrand48 (); |
|
} |
|
#else |
|
long random (); |
|
#endif |
|
|
|
/* It's a bit tricky to get this right, so please test the code well |
/* It's a bit tricky to get this right, so please test the code well if you |
if you hack with it. Some early versions of the function produced |
hack with it. Some early versions of the function produced random numbers |
random numbers with the leading limb == 0, and some versions never |
with the leading limb == 0, and some versions never made the most |
made the most significant bit set. */ |
significant bit set. |
|
|
void |
This code and mpz_rrandomb are almost identical, though the latter makes bit |
#if __STDC__ |
runs of 1 to 16, and doesn't force the first block to contain 1-bits. |
mpn_random2 (mp_ptr res_ptr, mp_size_t size) |
|
|
The RANDS random state currently produces 32 random bits per underlying lc |
|
invocation (BITS_PER_RANDCALL). We therefore ask for that, 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. 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 |
mpn_random2 (res_ptr, size) |
#define BITS_PER_RANDCALL 32 |
mp_ptr res_ptr; |
|
mp_size_t size; |
|
#endif |
#endif |
|
|
|
void |
|
mpn_random2 (mp_ptr rp, mp_size_t n) |
{ |
{ |
int n_bits; |
gmp_randstate_ptr rstate = RANDS; |
int bit_pos; |
int nb; |
mp_size_t limb_pos; |
int bit_pos; /* bit number of least significant bit where |
unsigned int ran; |
next bit field to be inserted */ |
mp_limb_t limb; |
mp_size_t ri; /* index in rp */ |
|
mp_limb_t ran, ranm; /* buffer for random bits */ |
|
mp_limb_t acc; /* accumulate output random data here */ |
|
int ran_nbits; /* number of valid bits in ran */ |
|
|
limb = 0; |
/* FIXME: Is n==0 supposed to be allowed? */ |
|
ASSERT (n >= 0); |
|
ASSERT_ALWAYS (BITS_PER_MP_LIMB > LOGBITS_PER_BLOCK); |
|
|
/* Start off in a random bit position in the most significant limb. */ |
_gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); |
bit_pos = random () & (BITS_PER_MP_LIMB - 1); |
ran = ranm; |
|
|
/* Least significant bit of RAN chooses string of ones/string of zeroes. |
/* Start off at a random bit position in the most significant limb. */ |
|
bit_pos = ran % GMP_NUMB_BITS; |
|
ran >>= 6; /* Ideally log2(GMP_NUMB_BITS) */ |
|
ran_nbits = BITS_PER_RANDCALL - 6; /* Ideally - log2(GMP_NUMB_BITS) */ |
|
|
|
/* Bit 0 of ran chooses string of ones/string of zeroes. |
Make most significant limb be non-zero by setting bit 0 of RAN. */ |
Make most significant limb be non-zero by setting bit 0 of RAN. */ |
ran = random () | 1; |
ran |= 1; |
|
|
for (limb_pos = size - 1; limb_pos >= 0; ) |
ri = n - 1; |
|
|
|
acc = 0; |
|
while (ri >= 0) |
{ |
{ |
n_bits = (ran >> 1) % BITS_PER_MP_LIMB + 1; |
if (ran_nbits < LOGBITS_PER_BLOCK + 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 (n_bits >= bit_pos) |
if (nb > bit_pos) |
{ |
{ |
res_ptr[limb_pos--] = limb | ((((mp_limb_t) 2) << bit_pos) - 1); |
rp[ri--] = acc | (((mp_limb_t) 2 << bit_pos) - 1); |
bit_pos += BITS_PER_MP_LIMB; |
bit_pos += GMP_NUMB_BITS; |
limb = (~(mp_limb_t) 0) << (bit_pos - n_bits); |
bit_pos -= nb; |
|
acc = ((~(mp_limb_t) 1) << bit_pos) & GMP_NUMB_MASK; |
} |
} |
else |
else |
{ |
{ |
limb |= ((((mp_limb_t) 1) << n_bits) - 1) << (bit_pos - n_bits + 1); |
bit_pos -= nb; |
|
acc |= (((mp_limb_t) 2 << nb) - 2) << bit_pos; |
} |
} |
} |
} |
else |
else |
{ |
{ |
/* Generate a string of zeroes. */ |
/* Generate a string of nb zeroes. */ |
if (n_bits >= bit_pos) |
if (nb > bit_pos) |
{ |
{ |
res_ptr[limb_pos--] = limb; |
rp[ri--] = acc; |
limb = 0; |
acc = 0; |
bit_pos += BITS_PER_MP_LIMB; |
bit_pos += GMP_NUMB_BITS; |
} |
} |
|
bit_pos -= nb; |
} |
} |
bit_pos -= n_bits; |
ran_nbits -= LOGBITS_PER_BLOCK + 1; |
ran = random (); |
ran >>= LOGBITS_PER_BLOCK + 1; |
} |
} |
} |
} |