[BACK]Return to randraw.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp

Annotation of OpenXM_contrib/gmp/randraw.c, Revision 1.1.1.2

1.1       maekawa     1: /* _gmp_rand (rp, state, nbits) -- Generate a random bitstream of
                      2:    length NBITS in RP.  RP must have enough space allocated to hold
                      3:    NBITS.
                      4:
1.1.1.2 ! ohara       5: Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
1.1       maekawa     6:
                      7: This file is part of the GNU MP Library.
                      8:
                      9: The GNU MP Library is free software; you can redistribute it and/or modify
                     10: it under the terms of the GNU Lesser General Public License as published by
                     11: the Free Software Foundation; either version 2.1 of the License, or (at your
                     12: option) any later version.
                     13:
                     14: The GNU MP Library is distributed in the hope that it will be useful, but
                     15: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     16: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     17: License for more details.
                     18:
                     19: You should have received a copy of the GNU Lesser General Public License
                     20: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     21: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     22: MA 02111-1307, USA. */
                     23:
                     24: #include "gmp.h"
                     25: #include "gmp-impl.h"
                     26: #include "longlong.h"
                     27:
                     28: /* For linear congruential (LC), we use one of algorithms (1) or (2).
                     29:    (gmp-3.0 uses algorithm (1) with 'm' as a power of 2.)
                     30:
                     31: LC algorithm (1).
                     32:
                     33:        X = (aX + c) mod m
                     34:
                     35: [D. Knuth, "The Art of Computer Programming: Volume 2, Seminumerical Algorithms",
                     36: Third Edition, Addison Wesley, 1998, pp. 184-185.]
                     37:
                     38:        X is the seed and the result
                     39:        a is chosen so that
                     40:            a mod 8 = 5 [3.2.1.2] and [3.2.1.3]
                     41:            .01m < a < .99m
                     42:            its binary or decimal digits is not a simple, regular pattern
                     43:            it has no large quotients when Euclid's algorithm is used to find
                     44:              gcd(a, m) [3.3.3]
                     45:            it passes the spectral test [3.3.4]
                     46:            it passes several tests of [3.3.2]
                     47:        c has no factor in common with m (c=1 or c=a can be good)
                     48:        m is large (2^30)
                     49:          is a power of 2 [3.2.1.1]
                     50:
                     51: The least significant digits of the generated number are not very
                     52: random.  It should be regarded as a random fraction X/m.  To get a
                     53: random integer between 0 and n-1, multiply X/m by n and truncate.
                     54: (Don't use X/n [ex 3.4.1-3])
                     55:
                     56: The ``accuracy'' in t dimensions is one part in ``the t'th root of m'' [3.3.4].
                     57:
                     58: Don't generate more than about m/1000 numbers without changing a, c, or m.
                     59:
                     60: The sequence length depends on chosen a,c,m.
                     61:
                     62:
                     63: LC algorithm (2).
                     64:
                     65:        X = a * (X mod q) - r * (long) (X/q)
                     66:        if X<0 then X+=m
                     67:
                     68: [Knuth, pp. 185-186.]
                     69:
                     70:        X is the seed and the result
                     71:          as a seed is nonzero and less than m
                     72:        a is a primitive root of m (which means that a^2 <= m)
                     73:        q is (long) m / a
                     74:        r is m mod a
                     75:        m is a prime number near the largest easily computed integer
                     76:
                     77: which gives
                     78:
                     79:        X = a * (X % ((long) m / a)) -
                     80:            (M % a) * ((long) (X / ((long) m / a)))
                     81:
                     82: Since m is prime, the least-significant bits of X are just as random as
                     83: the most-significant bits. */
                     84:
                     85:
                     86: /* lc (rp, state) -- Generate next number in LC sequence.  Return the
                     87:    number of valid bits in the result.  NOTE: If 'm' is a power of 2
                     88:    (m2exp != 0), discard the lower half of the result.  */
                     89:
                     90: static
                     91: unsigned long int
                     92: lc (mp_ptr rp, gmp_randstate_t rstate)
                     93: {
                     94:   mp_ptr tp, seedp, ap;
                     95:   mp_size_t ta;
                     96:   mp_size_t tn, seedn, an;
                     97:   unsigned long int m2exp;
                     98:   mp_limb_t c;
                     99:   TMP_DECL (mark);
                    100:
1.1.1.2 ! ohara     101:   m2exp = rstate->_mp_algdata._mp_lc->_mp_m2exp;
1.1       maekawa   102:
1.1.1.2 ! ohara     103:   /* The code below assumes the mod part is a power of two.  Make sure
        !           104:      that is the case.  */
        !           105:   ASSERT_ALWAYS (m2exp != 0);
        !           106:
        !           107:   c = (mp_limb_t) rstate->_mp_algdata._mp_lc->_mp_c;
        !           108:
        !           109:   seedp = PTR (rstate->_mp_seed);
        !           110:   seedn = SIZ (rstate->_mp_seed);
1.1       maekawa   111:
                    112:   if (seedn == 0)
                    113:     {
1.1.1.2 ! ohara     114:       /* Seed is 0.  Result is C % M.  Assume table is sensibly stored,
        !           115:        with C smaller than M*/
1.1       maekawa   116:       *rp = c;
                    117:
1.1.1.2 ! ohara     118:       *seedp = c;
        !           119:       SIZ (rstate->_mp_seed) = 1;
        !           120:       return m2exp;
1.1       maekawa   121:     }
                    122:
1.1.1.2 ! ohara     123:   ap = PTR (rstate->_mp_algdata._mp_lc->_mp_a);
        !           124:   an = SIZ (rstate->_mp_algdata._mp_lc->_mp_a);
1.1       maekawa   125:
                    126:   /* Allocate temporary storage.  Let there be room for calculation of
                    127:      (A * seed + C) % M, or M if bigger than that.  */
                    128:
                    129:   TMP_MARK (mark);
                    130:   ta = an + seedn + 1;
                    131:   tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB);
                    132:
                    133:   /* t = a * seed */
                    134:   if (seedn >= an)
1.1.1.2 ! ohara     135:     mpn_mul (tp, seedp, seedn, ap, an);
1.1       maekawa   136:   else
1.1.1.2 ! ohara     137:     mpn_mul (tp, ap, an, seedp, seedn);
1.1       maekawa   138:   tn = an + seedn;
                    139:
                    140:   /* t = t + c */
1.1.1.2 ! ohara     141:   tp[tn] = 0;                  /* sentinel, stops MPN_INCR_U */
        !           142:   MPN_INCR_U (tp, tn, c);
1.1       maekawa   143:
1.1.1.2 ! ohara     144:   ASSERT_ALWAYS (m2exp / GMP_NUMB_BITS < ta);
1.1       maekawa   145:
1.1.1.2 ! ohara     146:   /* t = t % m */
        !           147:   tp[m2exp / GMP_NUMB_BITS] &= ((mp_limb_t) 1 << m2exp % GMP_NUMB_BITS) - 1;
        !           148:   tn = (m2exp + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
1.1       maekawa   149:
                    150:   /* Save result as next seed.  */
1.1.1.2 ! ohara     151:   MPN_COPY (PTR (rstate->_mp_seed), tp, tn);
        !           152:   SIZ (rstate->_mp_seed) = tn;
1.1       maekawa   153:
1.1.1.2 ! ohara     154:   {
        !           155:     /* Discard the lower m2exp/2 bits of result.  */
        !           156:     unsigned long int bits = m2exp / 2;
        !           157:     mp_size_t xn = bits / GMP_NUMB_BITS;
        !           158:
        !           159:     tn -= xn;
        !           160:     if (tn > 0)
        !           161:       {
        !           162:        unsigned int cnt = bits % GMP_NUMB_BITS;
        !           163:        if (cnt != 0)
        !           164:          {
        !           165:            mpn_rshift (tp, tp + xn, tn, cnt);
        !           166:            MPN_COPY_INCR (rp, tp, xn + 1);
        !           167:          }
        !           168:        else                    /* Even limb boundary.  */
        !           169:          MPN_COPY_INCR (rp, tp + xn, tn);
        !           170:       }
        !           171:   }
1.1       maekawa   172:
                    173:   TMP_FREE (mark);
                    174:
                    175:   /* Return number of valid bits in the result.  */
1.1.1.2 ! ohara     176:   return (m2exp + 1) / 2;
1.1       maekawa   177: }
                    178:
                    179: #ifdef RAWRANDEBUG
                    180: /* Set even bits to EVENBITS and odd bits to ! EVENBITS in RP.
                    181:    Number of bits is m2exp in state.  */
                    182: /* FIXME: Remove.  */
                    183: unsigned long int
                    184: lc_test (mp_ptr rp, gmp_randstate_t s, const int evenbits)
                    185: {
                    186:   unsigned long int rn, nbits;
                    187:   int f;
                    188:
1.1.1.2 ! ohara     189:   nbits = s->_mp_algdata._mp_lc->_mp_m2exp / 2;
        !           190:   rn = nbits / GMP_NUMB_BITS + (nbits % GMP_NUMB_BITS != 0);
1.1       maekawa   191:   MPN_ZERO (rp, rn);
                    192:
                    193:   for (f = 0; f < nbits; f++)
                    194:     {
                    195:       mpn_lshift (rp, rp, rn, 1);
                    196:       if (f % 2 == ! evenbits)
                    197:        rp[0] += 1;
                    198:     }
                    199:
                    200:   return nbits;
                    201: }
                    202: #endif /* RAWRANDEBUG */
                    203:
                    204: void
                    205: _gmp_rand (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits)
                    206: {
                    207:   mp_size_t rn;                        /* Size of R.  */
                    208:
1.1.1.2 ! ohara     209:   rn = (nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
1.1       maekawa   210:
1.1.1.2 ! ohara     211:   switch (rstate->_mp_alg)
1.1       maekawa   212:     {
                    213:     case GMP_RAND_ALG_LC:
                    214:       {
                    215:        unsigned long int rbitpos;
                    216:        int chunk_nbits;
                    217:        mp_ptr tp;
                    218:        mp_size_t tn;
                    219:        TMP_DECL (lcmark);
                    220:
                    221:        TMP_MARK (lcmark);
                    222:
1.1.1.2 ! ohara     223:        chunk_nbits = rstate->_mp_algdata._mp_lc->_mp_m2exp / 2;
        !           224:        tn = (chunk_nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
1.1       maekawa   225:
                    226:        tp = (mp_ptr) TMP_ALLOC (tn * BYTES_PER_MP_LIMB);
                    227:
                    228:        rbitpos = 0;
                    229:        while (rbitpos + chunk_nbits <= nbits)
                    230:          {
1.1.1.2 ! ohara     231:            mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
1.1       maekawa   232:
1.1.1.2 ! ohara     233:            if (rbitpos % GMP_NUMB_BITS != 0)
1.1       maekawa   234:              {
                    235:                mp_limb_t savelimb, rcy;
                    236:                /* Target of of new chunk is not bit aligned.  Use temp space
                    237:                   and align things by shifting it up.  */
                    238:                lc (tp, rstate);
                    239:                savelimb = r2p[0];
1.1.1.2 ! ohara     240:                rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
1.1       maekawa   241:                r2p[0] |= savelimb;
1.1.1.2 ! ohara     242: /* bogus */    if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS)
        !           243:                    > GMP_NUMB_BITS)
1.1       maekawa   244:                  r2p[tn] = rcy;
                    245:              }
                    246:            else
                    247:              {
                    248:                /* Target of of new chunk is bit aligned.  Let `lc' put bits
                    249:                   directly into our target variable.  */
                    250:                lc (r2p, rstate);
                    251:              }
                    252:            rbitpos += chunk_nbits;
                    253:          }
                    254:
                    255:        /* Handle last [0..chunk_nbits) bits.  */
                    256:        if (rbitpos != nbits)
                    257:          {
1.1.1.2 ! ohara     258:            mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
1.1       maekawa   259:            int last_nbits = nbits - rbitpos;
1.1.1.2 ! ohara     260:            tn = (last_nbits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
1.1       maekawa   261:            lc (tp, rstate);
1.1.1.2 ! ohara     262:            if (rbitpos % GMP_NUMB_BITS != 0)
1.1       maekawa   263:              {
                    264:                mp_limb_t savelimb, rcy;
                    265:                /* Target of of new chunk is not bit aligned.  Use temp space
                    266:                   and align things by shifting it up.  */
                    267:                savelimb = r2p[0];
1.1.1.2 ! ohara     268:                rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
1.1       maekawa   269:                r2p[0] |= savelimb;
1.1.1.2 ! ohara     270:                if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits)
1.1       maekawa   271:                  r2p[tn] = rcy;
                    272:              }
                    273:            else
                    274:              {
                    275:                MPN_COPY (r2p, tp, tn);
                    276:              }
                    277:            /* Mask off top bits if needed.  */
1.1.1.2 ! ohara     278:            if (nbits % GMP_NUMB_BITS != 0)
        !           279:              rp[nbits / GMP_NUMB_BITS]
        !           280:                &= ~ ((~(mp_limb_t) 0) << nbits % GMP_NUMB_BITS);
1.1       maekawa   281:          }
                    282:
                    283:        TMP_FREE (lcmark);
                    284:        break;
                    285:       }
                    286:
                    287:     default:
1.1.1.2 ! ohara     288:       ASSERT (0);
1.1       maekawa   289:       break;
                    290:     }
                    291: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>