github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/rand/randlc2x.c (about)

     1  /* Linear Congruential pseudo-random number generator functions.
     2  
     3  Copyright 1999-2003, 2005 Free Software Foundation, Inc.
     4  
     5  This file is part of the GNU MP Library.
     6  
     7  The GNU MP Library is free software; you can redistribute it and/or modify
     8  it under the terms of either:
     9  
    10    * the GNU Lesser General Public License as published by the Free
    11      Software Foundation; either version 3 of the License, or (at your
    12      option) any later version.
    13  
    14  or
    15  
    16    * the GNU General Public License as published by the Free Software
    17      Foundation; either version 2 of the License, or (at your option) any
    18      later version.
    19  
    20  or both in parallel, as here.
    21  
    22  The GNU MP Library is distributed in the hope that it will be useful, but
    23  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    24  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    25  for more details.
    26  
    27  You should have received copies of the GNU General Public License and the
    28  GNU Lesser General Public License along with the GNU MP Library.  If not,
    29  see https://www.gnu.org/licenses/.  */
    30  
    31  #include "gmp.h"
    32  #include "gmp-impl.h"
    33  
    34  
    35  /* State structure for LC, the RNG_STATE() pointer in a gmp_randstate_t.
    36  
    37     _mp_seed holds the current seed value, in the range 0 to 2^m2exp-1.
    38     SIZ(_mp_seed) is fixed at BITS_TO_LIMBS(_mp_m2exp) and the value is
    39     padded with high zero limbs if necessary.  ALLOC(_mp_seed) is the current
    40     size of PTR(_mp_seed) in the usual way.  There only needs to be
    41     BITS_TO_LIMBS(_mp_m2exp) allocated, but the mpz functions in the
    42     initialization and seeding end up making it a bit more than this.
    43  
    44     _mp_a is the "a" multiplier, in the range 0 to 2^m2exp-1.  SIZ(_mp_a) is
    45     the size of the value in the normal way for an mpz_t, except that a value
    46     of zero is held with SIZ(_mp_a)==1 and PTR(_mp_a)[0]==0.  This makes it
    47     easy to call mpn_mul, and the case of a==0 is highly un-random and not
    48     worth any trouble to optimize.
    49  
    50     {_cp,_cn} is the "c" addend.  Normally _cn is 1, but when nails are in
    51     use a ulong can be bigger than one limb, and in this case _cn is 2 if
    52     necessary.  c==0 is stored as _cp[0]==0 and _cn==1, which makes it easy
    53     to call __GMPN_ADD.  c==0 is fairly un-random so isn't worth optimizing.
    54  
    55     _mp_m2exp gives the modulus, namely 2^m2exp.  We demand m2exp>=1, since
    56     m2exp==0 would mean no bits at all out of each iteration, which makes no
    57     sense.  */
    58  
    59  typedef struct {
    60    mpz_t          _mp_seed;
    61    mpz_t          _mp_a;
    62    mp_size_t      _cn;
    63    mp_limb_t      _cp[LIMBS_PER_ULONG];
    64    unsigned long  _mp_m2exp;
    65  } gmp_rand_lc_struct;
    66  
    67  
    68  /* lc (rp, state) -- Generate next number in LC sequence.  Return the
    69     number of valid bits in the result.  Discards the lower half of the
    70     result.  */
    71  
    72  static unsigned long int
    73  lc (mp_ptr rp, gmp_randstate_t rstate)
    74  {
    75    mp_ptr tp, seedp, ap;
    76    mp_size_t ta;
    77    mp_size_t tn, seedn, an;
    78    unsigned long int m2exp;
    79    unsigned long int bits;
    80    int cy;
    81    mp_size_t xn;
    82    gmp_rand_lc_struct *p;
    83    TMP_DECL;
    84  
    85    p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
    86  
    87    m2exp = p->_mp_m2exp;
    88  
    89    seedp = PTR (p->_mp_seed);
    90    seedn = SIZ (p->_mp_seed);
    91  
    92    ap = PTR (p->_mp_a);
    93    an = SIZ (p->_mp_a);
    94  
    95    /* Allocate temporary storage.  Let there be room for calculation of
    96       (A * seed + C) % M, or M if bigger than that.  */
    97  
    98    TMP_MARK;
    99  
   100    ta = an + seedn + 1;
   101    tn = BITS_TO_LIMBS (m2exp);
   102    if (ta <= tn) /* that is, if (ta < tn + 1) */
   103      {
   104        mp_size_t tmp = an + seedn;
   105        ta = tn + 1;
   106        tp = TMP_ALLOC_LIMBS (ta);
   107        MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out.  */
   108      }
   109    else
   110      tp = TMP_ALLOC_LIMBS (ta);
   111  
   112    /* t = a * seed.  NOTE: an is always > 0; see initialization.  */
   113    ASSERT (seedn >= an && an > 0);
   114    mpn_mul (tp, seedp, seedn, ap, an);
   115  
   116    /* t = t + c.  NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD);
   117       see initialization.  */
   118    ASSERT (tn >= p->_cn);
   119    __GMPN_ADD (cy, tp, tp, tn, p->_cp, p->_cn);
   120  
   121    /* t = t % m */
   122    tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1;
   123  
   124    /* Save result as next seed.  */
   125    MPN_COPY (PTR (p->_mp_seed), tp, tn);
   126  
   127    /* Discard the lower m2exp/2 of the result.  */
   128    bits = m2exp / 2;
   129    xn = bits / GMP_NUMB_BITS;
   130  
   131    tn -= xn;
   132    if (tn > 0)
   133      {
   134        unsigned int cnt = bits % GMP_NUMB_BITS;
   135        if (cnt != 0)
   136  	{
   137  	  mpn_rshift (tp, tp + xn, tn, cnt);
   138  	  MPN_COPY_INCR (rp, tp, xn + 1);
   139  	}
   140        else			/* Even limb boundary.  */
   141  	MPN_COPY_INCR (rp, tp + xn, tn);
   142      }
   143  
   144    TMP_FREE;
   145  
   146    /* Return number of valid bits in the result.  */
   147    return (m2exp + 1) / 2;
   148  }
   149  
   150  
   151  /* Obtain a sequence of random numbers.  */
   152  static void
   153  randget_lc (gmp_randstate_t rstate, mp_ptr rp, unsigned long int nbits)
   154  {
   155    unsigned long int rbitpos;
   156    int chunk_nbits;
   157    mp_ptr tp;
   158    mp_size_t tn;
   159    gmp_rand_lc_struct *p;
   160    TMP_DECL;
   161  
   162    p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
   163  
   164    TMP_MARK;
   165  
   166    chunk_nbits = p->_mp_m2exp / 2;
   167    tn = BITS_TO_LIMBS (chunk_nbits);
   168  
   169    tp = TMP_ALLOC_LIMBS (tn);
   170  
   171    rbitpos = 0;
   172    while (rbitpos + chunk_nbits <= nbits)
   173      {
   174        mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
   175  
   176        if (rbitpos % GMP_NUMB_BITS != 0)
   177  	{
   178  	  mp_limb_t savelimb, rcy;
   179  	  /* Target of new chunk is not bit aligned.  Use temp space
   180  	     and align things by shifting it up.  */
   181  	  lc (tp, rstate);
   182  	  savelimb = r2p[0];
   183  	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
   184  	  r2p[0] |= savelimb;
   185  	  /* bogus */
   186  	  if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS)
   187  	      > GMP_NUMB_BITS)
   188  	    r2p[tn] = rcy;
   189  	}
   190        else
   191  	{
   192  	  /* Target of new chunk is bit aligned.  Let `lc' put bits
   193  	     directly into our target variable.  */
   194  	  lc (r2p, rstate);
   195  	}
   196        rbitpos += chunk_nbits;
   197      }
   198  
   199    /* Handle last [0..chunk_nbits) bits.  */
   200    if (rbitpos != nbits)
   201      {
   202        mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
   203        int last_nbits = nbits - rbitpos;
   204        tn = BITS_TO_LIMBS (last_nbits);
   205        lc (tp, rstate);
   206        if (rbitpos % GMP_NUMB_BITS != 0)
   207  	{
   208  	  mp_limb_t savelimb, rcy;
   209  	  /* Target of new chunk is not bit aligned.  Use temp space
   210  	     and align things by shifting it up.  */
   211  	  savelimb = r2p[0];
   212  	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
   213  	  r2p[0] |= savelimb;
   214  	  if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits)
   215  	    r2p[tn] = rcy;
   216  	}
   217        else
   218  	{
   219  	  MPN_COPY (r2p, tp, tn);
   220  	}
   221        /* Mask off top bits if needed.  */
   222        if (nbits % GMP_NUMB_BITS != 0)
   223  	rp[nbits / GMP_NUMB_BITS]
   224  	  &= ~(~CNST_LIMB (0) << nbits % GMP_NUMB_BITS);
   225      }
   226  
   227    TMP_FREE;
   228  }
   229  
   230  
   231  static void
   232  randseed_lc (gmp_randstate_t rstate, mpz_srcptr seed)
   233  {
   234    gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
   235    mpz_ptr seedz = p->_mp_seed;
   236    mp_size_t seedn = BITS_TO_LIMBS (p->_mp_m2exp);
   237  
   238    /* Store p->_mp_seed as an unnormalized integer with size enough
   239       for numbers up to 2^m2exp-1.  That size can't be zero.  */
   240    mpz_fdiv_r_2exp (seedz, seed, p->_mp_m2exp);
   241    MPN_ZERO (&PTR (seedz)[SIZ (seedz)], seedn - SIZ (seedz));
   242    SIZ (seedz) = seedn;
   243  }
   244  
   245  
   246  static void
   247  randclear_lc (gmp_randstate_t rstate)
   248  {
   249    gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
   250  
   251    mpz_clear (p->_mp_seed);
   252    mpz_clear (p->_mp_a);
   253    (*__gmp_free_func) (p, sizeof (gmp_rand_lc_struct));
   254  }
   255  
   256  static void randiset_lc (gmp_randstate_ptr, gmp_randstate_srcptr);
   257  
   258  static const gmp_randfnptr_t Linear_Congruential_Generator = {
   259    randseed_lc,
   260    randget_lc,
   261    randclear_lc,
   262    randiset_lc
   263  };
   264  
   265  static void
   266  randiset_lc (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
   267  {
   268    gmp_rand_lc_struct *dstp, *srcp;
   269  
   270    srcp = (gmp_rand_lc_struct *) RNG_STATE (src);
   271    dstp = (gmp_rand_lc_struct *) (*__gmp_allocate_func) (sizeof (gmp_rand_lc_struct));
   272  
   273    RNG_STATE (dst) = (mp_limb_t *) (void *) dstp;
   274    RNG_FNPTR (dst) = (void *) &Linear_Congruential_Generator;
   275  
   276    /* _mp_seed and _mp_a might be unnormalized (high zero limbs), but
   277       mpz_init_set won't worry about that */
   278    mpz_init_set (dstp->_mp_seed, srcp->_mp_seed);
   279    mpz_init_set (dstp->_mp_a,    srcp->_mp_a);
   280  
   281    dstp->_cn = srcp->_cn;
   282  
   283    dstp->_cp[0] = srcp->_cp[0];
   284    if (LIMBS_PER_ULONG > 1)
   285      dstp->_cp[1] = srcp->_cp[1];
   286    if (LIMBS_PER_ULONG > 2)  /* usually there's only 1 or 2 */
   287      MPN_COPY (dstp->_cp + 2, srcp->_cp + 2, LIMBS_PER_ULONG - 2);
   288  
   289    dstp->_mp_m2exp = srcp->_mp_m2exp;
   290  }
   291  
   292  
   293  void
   294  gmp_randinit_lc_2exp (gmp_randstate_t rstate,
   295  		      mpz_srcptr a,
   296  		      unsigned long int c,
   297  		      mp_bitcnt_t m2exp)
   298  {
   299    gmp_rand_lc_struct *p;
   300    mp_size_t seedn = BITS_TO_LIMBS (m2exp);
   301  
   302    ASSERT_ALWAYS (m2exp != 0);
   303  
   304    p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct);
   305    RNG_STATE (rstate) = (mp_limb_t *) (void *) p;
   306    RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator;
   307  
   308    /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */
   309    mpz_init2 (p->_mp_seed, m2exp);
   310    MPN_ZERO (PTR (p->_mp_seed), seedn);
   311    SIZ (p->_mp_seed) = seedn;
   312    PTR (p->_mp_seed)[0] = 1;
   313  
   314    /* "a", forced to 0 to 2^m2exp-1 */
   315    mpz_init (p->_mp_a);
   316    mpz_fdiv_r_2exp (p->_mp_a, a, m2exp);
   317  
   318    /* Avoid SIZ(a) == 0 to avoid checking for special case in lc().  */
   319    if (SIZ (p->_mp_a) == 0)
   320      {
   321        SIZ (p->_mp_a) = 1;
   322        PTR (p->_mp_a)[0] = CNST_LIMB (0);
   323      }
   324  
   325    MPN_SET_UI (p->_cp, p->_cn, c);
   326  
   327    /* Internally we may discard any bits of c above m2exp.  The following
   328       code ensures that __GMPN_ADD in lc() will always work.  */
   329    if (seedn < p->_cn)
   330      p->_cn = (p->_cp[0] != 0);
   331  
   332    p->_mp_m2exp = m2exp;
   333  }