Coverage Report

Created: 2024-06-28 06:19

/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
}