Blame rand/randlc2x.c

Packit 5c3484
/* Linear Congruential pseudo-random number generator functions.
Packit 5c3484
Packit 5c3484
Copyright 1999-2003, 2005 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* State structure for LC, the RNG_STATE() pointer in a gmp_randstate_t.
Packit 5c3484
Packit 5c3484
   _mp_seed holds the current seed value, in the range 0 to 2^m2exp-1.
Packit 5c3484
   SIZ(_mp_seed) is fixed at BITS_TO_LIMBS(_mp_m2exp) and the value is
Packit 5c3484
   padded with high zero limbs if necessary.  ALLOC(_mp_seed) is the current
Packit 5c3484
   size of PTR(_mp_seed) in the usual way.  There only needs to be
Packit 5c3484
   BITS_TO_LIMBS(_mp_m2exp) allocated, but the mpz functions in the
Packit 5c3484
   initialization and seeding end up making it a bit more than this.
Packit 5c3484
Packit 5c3484
   _mp_a is the "a" multiplier, in the range 0 to 2^m2exp-1.  SIZ(_mp_a) is
Packit 5c3484
   the size of the value in the normal way for an mpz_t, except that a value
Packit 5c3484
   of zero is held with SIZ(_mp_a)==1 and PTR(_mp_a)[0]==0.  This makes it
Packit 5c3484
   easy to call mpn_mul, and the case of a==0 is highly un-random and not
Packit 5c3484
   worth any trouble to optimize.
Packit 5c3484
Packit 5c3484
   {_cp,_cn} is the "c" addend.  Normally _cn is 1, but when nails are in
Packit 5c3484
   use a ulong can be bigger than one limb, and in this case _cn is 2 if
Packit 5c3484
   necessary.  c==0 is stored as _cp[0]==0 and _cn==1, which makes it easy
Packit 5c3484
   to call __GMPN_ADD.  c==0 is fairly un-random so isn't worth optimizing.
Packit 5c3484
Packit 5c3484
   _mp_m2exp gives the modulus, namely 2^m2exp.  We demand m2exp>=1, since
Packit 5c3484
   m2exp==0 would mean no bits at all out of each iteration, which makes no
Packit 5c3484
   sense.  */
Packit 5c3484
Packit 5c3484
typedef struct {
Packit 5c3484
  mpz_t          _mp_seed;
Packit 5c3484
  mpz_t          _mp_a;
Packit 5c3484
  mp_size_t      _cn;
Packit 5c3484
  mp_limb_t      _cp[LIMBS_PER_ULONG];
Packit 5c3484
  unsigned long  _mp_m2exp;
Packit 5c3484
} gmp_rand_lc_struct;
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* lc (rp, state) -- Generate next number in LC sequence.  Return the
Packit 5c3484
   number of valid bits in the result.  Discards the lower half of the
Packit 5c3484
   result.  */
Packit 5c3484
Packit 5c3484
static unsigned long int
Packit 5c3484
lc (mp_ptr rp, gmp_randstate_t rstate)
Packit 5c3484
{
Packit 5c3484
  mp_ptr tp, seedp, ap;
Packit 5c3484
  mp_size_t ta;
Packit 5c3484
  mp_size_t tn, seedn, an;
Packit 5c3484
  unsigned long int m2exp;
Packit 5c3484
  unsigned long int bits;
Packit 5c3484
  int cy;
Packit 5c3484
  mp_size_t xn;
Packit 5c3484
  gmp_rand_lc_struct *p;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
Packit 5c3484
Packit 5c3484
  m2exp = p->_mp_m2exp;
Packit 5c3484
Packit 5c3484
  seedp = PTR (p->_mp_seed);
Packit 5c3484
  seedn = SIZ (p->_mp_seed);
Packit 5c3484
Packit 5c3484
  ap = PTR (p->_mp_a);
Packit 5c3484
  an = SIZ (p->_mp_a);
Packit 5c3484
Packit 5c3484
  /* Allocate temporary storage.  Let there be room for calculation of
Packit 5c3484
     (A * seed + C) % M, or M if bigger than that.  */
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  ta = an + seedn + 1;
Packit 5c3484
  tn = BITS_TO_LIMBS (m2exp);
Packit 5c3484
  if (ta <= tn) /* that is, if (ta < tn + 1) */
Packit 5c3484
    {
Packit 5c3484
      mp_size_t tmp = an + seedn;
Packit 5c3484
      ta = tn + 1;
Packit 5c3484
      tp = TMP_ALLOC_LIMBS (ta);
Packit 5c3484
      MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out.  */
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    tp = TMP_ALLOC_LIMBS (ta);
Packit 5c3484
Packit 5c3484
  /* t = a * seed.  NOTE: an is always > 0; see initialization.  */
Packit 5c3484
  ASSERT (seedn >= an && an > 0);
Packit 5c3484
  mpn_mul (tp, seedp, seedn, ap, an);
Packit 5c3484
Packit 5c3484
  /* t = t + c.  NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD);
Packit 5c3484
     see initialization.  */
Packit 5c3484
  ASSERT (tn >= p->_cn);
Packit 5c3484
  __GMPN_ADD (cy, tp, tp, tn, p->_cp, p->_cn);
Packit 5c3484
Packit 5c3484
  /* t = t % m */
Packit 5c3484
  tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1;
Packit 5c3484
Packit 5c3484
  /* Save result as next seed.  */
Packit 5c3484
  MPN_COPY (PTR (p->_mp_seed), tp, tn);
Packit 5c3484
Packit 5c3484
  /* Discard the lower m2exp/2 of the result.  */
Packit 5c3484
  bits = m2exp / 2;
Packit 5c3484
  xn = bits / GMP_NUMB_BITS;
Packit 5c3484
Packit 5c3484
  tn -= xn;
Packit 5c3484
  if (tn > 0)
Packit 5c3484
    {
Packit 5c3484
      unsigned int cnt = bits % GMP_NUMB_BITS;
Packit 5c3484
      if (cnt != 0)
Packit 5c3484
	{
Packit 5c3484
	  mpn_rshift (tp, tp + xn, tn, cnt);
Packit 5c3484
	  MPN_COPY_INCR (rp, tp, xn + 1);
Packit 5c3484
	}
Packit 5c3484
      else			/* Even limb boundary.  */
Packit 5c3484
	MPN_COPY_INCR (rp, tp + xn, tn);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  TMP_FREE;
Packit 5c3484
Packit 5c3484
  /* Return number of valid bits in the result.  */
Packit 5c3484
  return (m2exp + 1) / 2;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Obtain a sequence of random numbers.  */
Packit 5c3484
static void
Packit 5c3484
randget_lc (gmp_randstate_t rstate, mp_ptr rp, unsigned long int nbits)
Packit 5c3484
{
Packit 5c3484
  unsigned long int rbitpos;
Packit 5c3484
  int chunk_nbits;
Packit 5c3484
  mp_ptr tp;
Packit 5c3484
  mp_size_t tn;
Packit 5c3484
  gmp_rand_lc_struct *p;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  chunk_nbits = p->_mp_m2exp / 2;
Packit 5c3484
  tn = BITS_TO_LIMBS (chunk_nbits);
Packit 5c3484
Packit 5c3484
  tp = TMP_ALLOC_LIMBS (tn);
Packit 5c3484
Packit 5c3484
  rbitpos = 0;
Packit 5c3484
  while (rbitpos + chunk_nbits <= nbits)
Packit 5c3484
    {
Packit 5c3484
      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
Packit 5c3484
Packit 5c3484
      if (rbitpos % GMP_NUMB_BITS != 0)
Packit 5c3484
	{
Packit 5c3484
	  mp_limb_t savelimb, rcy;
Packit 5c3484
	  /* Target of new chunk is not bit aligned.  Use temp space
Packit 5c3484
	     and align things by shifting it up.  */
Packit 5c3484
	  lc (tp, rstate);
Packit 5c3484
	  savelimb = r2p[0];
Packit 5c3484
	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
Packit 5c3484
	  r2p[0] |= savelimb;
Packit 5c3484
	  /* bogus */
Packit 5c3484
	  if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS)
Packit 5c3484
	      > GMP_NUMB_BITS)
Packit 5c3484
	    r2p[tn] = rcy;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  /* Target of new chunk is bit aligned.  Let `lc' put bits
Packit 5c3484
	     directly into our target variable.  */
Packit 5c3484
	  lc (r2p, rstate);
Packit 5c3484
	}
Packit 5c3484
      rbitpos += chunk_nbits;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Handle last [0..chunk_nbits) bits.  */
Packit 5c3484
  if (rbitpos != nbits)
Packit 5c3484
    {
Packit 5c3484
      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
Packit 5c3484
      int last_nbits = nbits - rbitpos;
Packit 5c3484
      tn = BITS_TO_LIMBS (last_nbits);
Packit 5c3484
      lc (tp, rstate);
Packit 5c3484
      if (rbitpos % GMP_NUMB_BITS != 0)
Packit 5c3484
	{
Packit 5c3484
	  mp_limb_t savelimb, rcy;
Packit 5c3484
	  /* Target of new chunk is not bit aligned.  Use temp space
Packit 5c3484
	     and align things by shifting it up.  */
Packit 5c3484
	  savelimb = r2p[0];
Packit 5c3484
	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
Packit 5c3484
	  r2p[0] |= savelimb;
Packit 5c3484
	  if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits)
Packit 5c3484
	    r2p[tn] = rcy;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  MPN_COPY (r2p, tp, tn);
Packit 5c3484
	}
Packit 5c3484
      /* Mask off top bits if needed.  */
Packit 5c3484
      if (nbits % GMP_NUMB_BITS != 0)
Packit 5c3484
	rp[nbits / GMP_NUMB_BITS]
Packit 5c3484
	  &= ~(~CNST_LIMB (0) << nbits % GMP_NUMB_BITS);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  TMP_FREE;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
static void
Packit 5c3484
randseed_lc (gmp_randstate_t rstate, mpz_srcptr seed)
Packit 5c3484
{
Packit 5c3484
  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
Packit 5c3484
  mpz_ptr seedz = p->_mp_seed;
Packit 5c3484
  mp_size_t seedn = BITS_TO_LIMBS (p->_mp_m2exp);
Packit 5c3484
Packit 5c3484
  /* Store p->_mp_seed as an unnormalized integer with size enough
Packit 5c3484
     for numbers up to 2^m2exp-1.  That size can't be zero.  */
Packit 5c3484
  mpz_fdiv_r_2exp (seedz, seed, p->_mp_m2exp);
Packit 5c3484
  MPN_ZERO (&PTR (seedz)[SIZ (seedz)], seedn - SIZ (seedz));
Packit 5c3484
  SIZ (seedz) = seedn;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
static void
Packit 5c3484
randclear_lc (gmp_randstate_t rstate)
Packit 5c3484
{
Packit 5c3484
  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
Packit 5c3484
Packit 5c3484
  mpz_clear (p->_mp_seed);
Packit 5c3484
  mpz_clear (p->_mp_a);
Packit 5c3484
  (*__gmp_free_func) (p, sizeof (gmp_rand_lc_struct));
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
static void randiset_lc (gmp_randstate_ptr, gmp_randstate_srcptr);
Packit 5c3484
Packit 5c3484
static const gmp_randfnptr_t Linear_Congruential_Generator = {
Packit 5c3484
  randseed_lc,
Packit 5c3484
  randget_lc,
Packit 5c3484
  randclear_lc,
Packit 5c3484
  randiset_lc
Packit 5c3484
};
Packit 5c3484
Packit 5c3484
static void
Packit 5c3484
randiset_lc (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
Packit 5c3484
{
Packit 5c3484
  gmp_rand_lc_struct *dstp, *srcp;
Packit 5c3484
Packit 5c3484
  srcp = (gmp_rand_lc_struct *) RNG_STATE (src);
Packit 5c3484
  dstp = (gmp_rand_lc_struct *) (*__gmp_allocate_func) (sizeof (gmp_rand_lc_struct));
Packit 5c3484
Packit 5c3484
  RNG_STATE (dst) = (mp_limb_t *) (void *) dstp;
Packit 5c3484
  RNG_FNPTR (dst) = (void *) &Linear_Congruential_Generator;
Packit 5c3484
Packit 5c3484
  /* _mp_seed and _mp_a might be unnormalized (high zero limbs), but
Packit 5c3484
     mpz_init_set won't worry about that */
Packit 5c3484
  mpz_init_set (dstp->_mp_seed, srcp->_mp_seed);
Packit 5c3484
  mpz_init_set (dstp->_mp_a,    srcp->_mp_a);
Packit 5c3484
Packit 5c3484
  dstp->_cn = srcp->_cn;
Packit 5c3484
Packit 5c3484
  dstp->_cp[0] = srcp->_cp[0];
Packit 5c3484
  if (LIMBS_PER_ULONG > 1)
Packit 5c3484
    dstp->_cp[1] = srcp->_cp[1];
Packit 5c3484
  if (LIMBS_PER_ULONG > 2)  /* usually there's only 1 or 2 */
Packit 5c3484
    MPN_COPY (dstp->_cp + 2, srcp->_cp + 2, LIMBS_PER_ULONG - 2);
Packit 5c3484
Packit 5c3484
  dstp->_mp_m2exp = srcp->_mp_m2exp;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
gmp_randinit_lc_2exp (gmp_randstate_t rstate,
Packit 5c3484
		      mpz_srcptr a,
Packit 5c3484
		      unsigned long int c,
Packit 5c3484
		      mp_bitcnt_t m2exp)
Packit 5c3484
{
Packit 5c3484
  gmp_rand_lc_struct *p;
Packit 5c3484
  mp_size_t seedn = BITS_TO_LIMBS (m2exp);
Packit 5c3484
Packit 5c3484
  ASSERT_ALWAYS (m2exp != 0);
Packit 5c3484
Packit 5c3484
  p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct);
Packit 5c3484
  RNG_STATE (rstate) = (mp_limb_t *) (void *) p;
Packit 5c3484
  RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator;
Packit 5c3484
Packit 5c3484
  /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */
Packit 5c3484
  mpz_init2 (p->_mp_seed, m2exp);
Packit 5c3484
  MPN_ZERO (PTR (p->_mp_seed), seedn);
Packit 5c3484
  SIZ (p->_mp_seed) = seedn;
Packit 5c3484
  PTR (p->_mp_seed)[0] = 1;
Packit 5c3484
Packit 5c3484
  /* "a", forced to 0 to 2^m2exp-1 */
Packit 5c3484
  mpz_init (p->_mp_a);
Packit 5c3484
  mpz_fdiv_r_2exp (p->_mp_a, a, m2exp);
Packit 5c3484
Packit 5c3484
  /* Avoid SIZ(a) == 0 to avoid checking for special case in lc().  */
Packit 5c3484
  if (SIZ (p->_mp_a) == 0)
Packit 5c3484
    {
Packit 5c3484
      SIZ (p->_mp_a) = 1;
Packit 5c3484
      PTR (p->_mp_a)[0] = CNST_LIMB (0);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  MPN_SET_UI (p->_cp, p->_cn, c);
Packit 5c3484
Packit 5c3484
  /* Internally we may discard any bits of c above m2exp.  The following
Packit 5c3484
     code ensures that __GMPN_ADD in lc() will always work.  */
Packit 5c3484
  if (seedn < p->_cn)
Packit 5c3484
    p->_cn = (p->_cp[0] != 0);
Packit 5c3484
Packit 5c3484
  p->_mp_m2exp = m2exp;
Packit 5c3484
}