/src/gmp-6.2.1/rand/randmts.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Mersenne Twister pseudo-random number generator functions. |
2 | | |
3 | | Copyright 2002, 2003, 2013, 2014 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-impl.h" |
32 | | #include "randmt.h" |
33 | | |
34 | | |
35 | | /* Calculate (b^e) mod (2^n-k) for e=1074888996, n=19937 and k=20023, |
36 | | needed by the seeding function below. */ |
37 | | static void |
38 | | mangle_seed (mpz_ptr r) |
39 | 2 | { |
40 | 2 | mpz_t t, b; |
41 | 2 | unsigned long e = 0x40118124; |
42 | 2 | unsigned long bit = 0x20000000; |
43 | | |
44 | 2 | mpz_init2 (t, 19937L); |
45 | 2 | mpz_init_set (b, r); |
46 | | |
47 | 2 | do |
48 | 60 | { |
49 | 60 | mpz_mul (r, r, r); |
50 | | |
51 | 72 | reduce: |
52 | 72 | for (;;) |
53 | 166 | { |
54 | 166 | mpz_tdiv_q_2exp (t, r, 19937L); |
55 | 166 | if (SIZ (t) == 0) |
56 | 72 | break; |
57 | 94 | mpz_tdiv_r_2exp (r, r, 19937L); |
58 | 94 | mpz_addmul_ui (r, t, 20023L); |
59 | 94 | } |
60 | | |
61 | 72 | if ((e & bit) != 0) |
62 | 12 | { |
63 | 12 | e ^= bit; |
64 | 12 | mpz_mul (r, r, b); |
65 | 12 | goto reduce; |
66 | 12 | } |
67 | | |
68 | 60 | bit >>= 1; |
69 | 60 | } |
70 | 60 | while (bit != 0); |
71 | | |
72 | 2 | mpz_clear (t); |
73 | 2 | mpz_clear (b); |
74 | 2 | } |
75 | | |
76 | | |
77 | | /* Seeding function. Uses powering modulo a non-Mersenne prime to obtain |
78 | | a permutation of the input seed space. The modulus is 2^19937-20023, |
79 | | which is probably prime. The power is 1074888996. In order to avoid |
80 | | seeds 0 and 1 generating invalid or strange output, the input seed is |
81 | | first manipulated as follows: |
82 | | |
83 | | seed1 = seed mod (2^19937-20027) + 2 |
84 | | |
85 | | so that seed1 lies between 2 and 2^19937-20026 inclusive. Then the |
86 | | powering is performed as follows: |
87 | | |
88 | | seed2 = (seed1^1074888996) mod (2^19937-20023) |
89 | | |
90 | | and then seed2 is used to bootstrap the buffer. |
91 | | |
92 | | This method aims to give guarantees that: |
93 | | a) seed2 will never be zero, |
94 | | b) seed2 will very seldom have a very low population of ones in its |
95 | | binary representation, and |
96 | | c) every seed between 0 and 2^19937-20028 (inclusive) will yield a |
97 | | different sequence. |
98 | | |
99 | | CAVEATS: |
100 | | |
101 | | The period of the seeding function is 2^19937-20027. This means that |
102 | | with seeds 2^19937-20027, 2^19937-20026, ... the exact same sequences |
103 | | are obtained as with seeds 0, 1, etc.; it also means that seed -1 |
104 | | produces the same sequence as seed 2^19937-20028, etc. |
105 | | */ |
106 | | |
107 | | static void |
108 | | randseed_mt (gmp_randstate_t rstate, mpz_srcptr seed) |
109 | 2 | { |
110 | 2 | int i; |
111 | 2 | size_t cnt; |
112 | | |
113 | 2 | gmp_rand_mt_struct *p; |
114 | 2 | mpz_t mod; /* Modulus. */ |
115 | 2 | mpz_t seed1; /* Intermediate result. */ |
116 | | |
117 | 2 | p = (gmp_rand_mt_struct *) RNG_STATE (rstate); |
118 | | |
119 | 2 | mpz_init2 (mod, 19938L); |
120 | 2 | mpz_init2 (seed1, 19937L); |
121 | | |
122 | 2 | mpz_setbit (mod, 19937L); |
123 | 2 | mpz_sub_ui (mod, mod, 20027L); |
124 | 2 | mpz_mod (seed1, seed, mod); /* Reduce `seed' modulo `mod'. */ |
125 | 2 | mpz_clear (mod); |
126 | 2 | mpz_add_ui (seed1, seed1, 2L); /* seed1 is now ready. */ |
127 | 2 | mangle_seed (seed1); /* Perform the mangling by powering. */ |
128 | | |
129 | | /* Copy the last bit into bit 31 of mt[0] and clear it. */ |
130 | 2 | p->mt[0] = (mpz_tstbit (seed1, 19936L) != 0) ? 0x80000000 : 0; |
131 | 2 | mpz_clrbit (seed1, 19936L); |
132 | | |
133 | | /* Split seed1 into N-1 32-bit chunks. */ |
134 | 2 | mpz_export (&p->mt[1], &cnt, -1, sizeof (p->mt[1]), 0, |
135 | 2 | 8 * sizeof (p->mt[1]) - 32, seed1); |
136 | 2 | mpz_clear (seed1); |
137 | 2 | cnt++; |
138 | 2 | ASSERT (cnt <= N); |
139 | 2 | while (cnt < N) |
140 | 0 | p->mt[cnt++] = 0; |
141 | | |
142 | | /* Warm the generator up if necessary. */ |
143 | 2 | if (WARM_UP != 0) |
144 | 8 | for (i = 0; i < WARM_UP / N; i++) |
145 | 6 | __gmp_mt_recalc_buffer (p->mt); |
146 | | |
147 | 2 | p->mti = WARM_UP % N; |
148 | 2 | } |
149 | | |
150 | | |
151 | | static const gmp_randfnptr_t Mersenne_Twister_Generator = { |
152 | | randseed_mt, |
153 | | __gmp_randget_mt, |
154 | | __gmp_randclear_mt, |
155 | | __gmp_randiset_mt |
156 | | }; |
157 | | |
158 | | /* Initialize MT-specific data. */ |
159 | | void |
160 | | gmp_randinit_mt (gmp_randstate_t rstate) |
161 | 2 | { |
162 | 2 | __gmp_randinit_mt_noseed (rstate); |
163 | 2 | RNG_FNPTR (rstate) = (void *) &Mersenne_Twister_Generator; |
164 | 2 | } |