View Javadoc
1   package nl.tudelft.simulation.jstats.streams;
2   
3   /**
4    * A java implementation of the Mersenne Twister pseudo random number generator.
5    * <p>
6    * This is a Java version of the C-program for MT19937: Integer version. genrand() generates one pseudorandom unsigned integer
7    * (32bit) which is uniformly distributed among 0 to 2^32-1 for each call. sgenrand(seed) set initial values to the working area
8    * of 624 words. (seed is any 32-bit integer except for 0).
9    * </p>
10   * <p>
11   * Orignally Coded by Takuji Nishimura, considering the suggestions by Topher Cooper and Marc Rieffel in July-Aug. 1997. More
12   * information can be found at <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf">
13   * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf</a> and
14   * <a href="https://en.wikipedia.org/wiki/Mersenne_Twister"> https://en.wikipedia.org/wiki/Mersenne_Twister</a>.
15   * </p>
16   * <p>
17   * Copyright (c) 2002-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
18   * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
19   * project is distributed under a three-clause BSD-style license, which can be found at
20   * <a href="https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
21   * </p>
22   * @author <a href="https://github.com/averbraeck" target="_blank"> Alexander Verbraeck</a>
23   * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
24   */
25  public class MersenneTwister extends RandomNumberGenerator
26  {
27      /** */
28      private static final long serialVersionUID = 20150426L;
29  
30      /** Period parameter N. */
31      private static final int N = 624;
32  
33      /** Period parameter M. */
34      private static final int M = 397;
35  
36      /** constant vector a. */
37      private static final int MATRIX_A = 0x9908b0df;
38  
39      /** most significant w-r bits. */
40      private static final int UPPER_MASK = 0x80000000;
41  
42      /** least significant w-r bits. */
43      private static final int LOWER_MASK = 0x7fffffff;
44  
45      /** tempering mask b. */
46      private static final int TEMPERING_MASK_B = 0x9d2c5680;
47  
48      /** tempering mask b. */
49      private static final int TEMPERING_MASK_C = 0xefc60000;
50  
51      /** unsigned mask for promoting int -> long. */
52      private static final int UMASK = (1 << 31) - 1;
53  
54      /** the array for the state vector. */
55      private int[] mt;
56  
57      /** The counter mti==N+1 means mt[N] is not initialized. */
58      private int mti;
59  
60      /** magic01. */
61      private int[] mag01;
62  
63      /**
64       * constructs a new Mersenne Twister. <code>System.currentTimeMillis()</code> is used as seed value.
65       */
66      public MersenneTwister()
67      {
68          this(System.currentTimeMillis());
69      }
70  
71      /**
72       * Constructor using a given seed.
73       * @param seed long; The initial seed.
74       */
75      public MersenneTwister(final long seed)
76      {
77          super(seed);
78      }
79  
80      /**
81       * initalizes the MersenneTwister.
82       */
83      private void initialize()
84      {
85          this.mt = new int[N];
86  
87          this.mt[0] = ((int) super.seed) & UMASK;
88          if (this.mt[0] == 0)
89          {
90              // super.seed=Integer.MAXValue --> seed & UMASK==0
91              // We set the seed again and enforce a different value.
92              this.setSeed(System.currentTimeMillis());
93          }
94          for (this.mti = 1; this.mti < N; this.mti++)
95          {
96              this.mt[this.mti] = (69069 * this.mt[this.mti - 1]);
97          }
98  
99          // mag01[x] = x * MATRIX_A for x=0,1
100         this.mag01 = new int[2];
101         this.mag01[0] = 0x0;
102         this.mag01[1] = MATRIX_A;
103     }
104 
105     @Override
106     public synchronized long next(final int bits)
107     {
108         if (bits < 0 || bits > 64)
109         {
110             throw new IllegalArgumentException("bits (" + bits + ") not in range [0,64]");
111         }
112         int y;
113         if (this.mti >= N) // generate N words at one time
114         {
115             int kk;
116             for (kk = 0; kk < N - M; kk++)
117             {
118                 y = (this.mt[kk] & UPPER_MASK) | (this.mt[kk + 1] & LOWER_MASK);
119                 this.mt[kk] = this.mt[kk + M] ^ (y >>> 1) ^ this.mag01[y & 0x1];
120             }
121             for (; kk < N - 1; kk++)
122             {
123                 y = (this.mt[kk] & UPPER_MASK) | (this.mt[kk + 1] & LOWER_MASK);
124                 this.mt[kk] = this.mt[kk + (M - N)] ^ (y >>> 1) ^ this.mag01[y & 0x1];
125             }
126             y = (this.mt[N - 1] & UPPER_MASK) | (this.mt[0] & LOWER_MASK);
127             this.mt[N - 1] = this.mt[M - 1] ^ (y >>> 1) ^ this.mag01[y & 0x1];
128             this.mti = 0;
129         }
130         y = this.mt[this.mti++];
131         y ^= y >>> 11; // TEMPERING_SHIFT_U(y)
132         y ^= (y << 7) & TEMPERING_MASK_B; // TEMPERING_SHIFT_S(y)
133         y ^= (y << 15) & TEMPERING_MASK_C; // TEMPERING_SHIFT_T(y)
134         y ^= (y >>> 18); // TEMPERING_SHIFT_L(y)
135         if (bits <= 32)
136         {
137             return y >>> (32 - bits);
138         }
139         return y << 32 + this.next(bits - 32);
140     }
141 
142     @Override
143     public synchronized void setSeed(final long seed)
144     {
145         super.seed = seed;
146         this.initialize();
147     }
148 }