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/. */
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
52 mp_limb_t _cp
[LIMBS_PER_ULONG
];
53 unsigned long _mp_m2exp
;
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
61 static unsigned long int
62 lc (mp_ptr rp
, gmp_randstate_t rstate
)
66 mp_size_t tn
, seedn
, an
;
67 unsigned long int m2exp
;
68 unsigned long int bits
;
71 gmp_rand_lc_struct
*p
;
74 p
= (gmp_rand_lc_struct
*) RNG_STATE (rstate
);
78 seedp
= PTR (p
->_mp_seed
);
79 seedn
= SIZ (p
->_mp_seed
);
84 /* Allocate temporary storage. Let there be room for calculation of
85 (A * seed + C) % M, or M if bigger than that. */
90 tn
= BITS_TO_LIMBS (m2exp
);
91 if (ta
<= tn
) /* that is, if (ta < tn + 1) */
93 mp_size_t tmp
= an
+ seedn
;
95 tp
= TMP_ALLOC_LIMBS (ta
);
96 MPN_ZERO (&tp
[tmp
], ta
- tmp
); /* mpn_mul won't zero it out. */
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
);
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. */
118 xn
= bits
/ GMP_NUMB_BITS
;
123 unsigned int cnt
= bits
% GMP_NUMB_BITS
;
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
);
135 /* Return number of valid bits in the result. */
136 return (m2exp
+ 1) / 2;
140 /* Obtain a sequence of random numbers. */
142 randget_lc (gmp_randstate_t rstate
, mp_ptr rp
, unsigned long int nbits
)
144 unsigned long int rbitpos
;
148 gmp_rand_lc_struct
*p
;
151 p
= (gmp_rand_lc_struct
*) RNG_STATE (rstate
);
155 chunk_nbits
= p
->_mp_m2exp
/ 2;
156 tn
= BITS_TO_LIMBS (chunk_nbits
);
158 tp
= TMP_ALLOC_LIMBS (tn
);
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. */
172 rcy
= mpn_lshift (r2p
, tp
, tn
, rbitpos
% GMP_NUMB_BITS
);
175 if ((chunk_nbits
% GMP_NUMB_BITS
+ rbitpos
% GMP_NUMB_BITS
)
181 /* Target of new chunk is bit aligned. Let `lc' put bits
182 directly into our target variable. */
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
);
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. */
201 rcy
= mpn_lshift (r2p
, tp
, tn
, rbitpos
% GMP_NUMB_BITS
);
203 if (rbitpos
+ tn
* GMP_NUMB_BITS
- rbitpos
% GMP_NUMB_BITS
< nbits
)
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
);
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
));
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
= {
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
;
283 gmp_randinit_lc_2exp (gmp_randstate_t rstate
,
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 */
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)
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. */
319 p
->_cn
= (p
->_cp
[0] != 0);
321 p
->_mp_m2exp
= m2exp
;