randlc2x.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:9k
源码类别:

数学计算

开发平台:

Unix_Linux

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