X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gmp%2Fmpn%2Fgeneric%2Frandom2.c;fp=gmp%2Fmpn%2Fgeneric%2Frandom2.c;h=e29238c51466fc7db3de28be4a86b2905b746eec;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gmp/mpn/generic/random2.c b/gmp/mpn/generic/random2.c new file mode 100644 index 00000000..e29238c5 --- /dev/null +++ b/gmp/mpn/generic/random2.c @@ -0,0 +1,96 @@ +/* mpn_random2 -- Generate random numbers with relatively long strings + of ones and zeroes. Suitable for border testing. + +Copyright 1992, 1993, 1994, 1996, 2000, 2001, 2002, 2004 Free Software +Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + +#include "gmp.h" +#include "gmp-impl.h" + +static void gmp_rrandomb __GMP_PROTO ((mp_ptr, gmp_randstate_t, unsigned long int)); + +/* 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 +#define BITS_PER_RANDCALL 32 +#endif + +void +mpn_random2 (mp_ptr rp, mp_size_t n) +{ + gmp_randstate_ptr rstate = RANDS; + int bit_pos; /* bit number of least significant bit where + next bit field to be inserted */ + mp_limb_t ran, ranm; /* buffer for random bits */ + + /* FIXME: Is n==0 supposed to be allowed? */ + ASSERT (n >= 0); + + _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL); + ran = ranm; + + /* Start off at a random bit position in the most significant limb. */ + bit_pos = ran % GMP_NUMB_BITS; + + gmp_rrandomb (rp, rstate, n * GMP_NUMB_BITS - bit_pos); +} + +static void +gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits) +{ + unsigned long int bi; + mp_limb_t ranm; /* buffer for random bits */ + unsigned cap_chunksize, chunksize; + mp_size_t i; + + /* Set entire result to 111..1 */ + i = (nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS - 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 */ + } +}