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