1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/* Mersenne Twister 移植
 * Leonardone @ NEETSDKASU
 * BSD-2-Clause License
 */

//! メルセンヌツイスタをRustに移植してみたもの。正しく移植・実装できているかの保証はできません。  
//!
//! 移植元のライセンスに関してはソースコード下部に記載してあります。
//!
//! # Example
//!
//! ```
//! use mersenne_twister_rs::MersenneTwister;
//! let seed: u32 = 12_3456_7890;
//! let mut mt = Box::new(MersenneTwister::new(seed));
//! println!("u32 [0,0xffffffff] value: {}", mt.genrand_u32());
//! println!("i32 [0,0x7fffffff] value: {}", mt.genrand_i31());
//! println!("f64 [0,1) value: {}", mt.genrand_real2());
//! ```

const N: usize = 624;
const M: usize = 397;
const MATRIX_A: u32 = 0x9908b0df_u32;
const UPPER_MASK: u32 = 0x80000000_u32;
const LOWER_MASK: u32 = 0x7fffffff_u32;

/// デフォルトとして使用されるSEED。  
///
/// ※本番環境での使用は推奨しません。  
///
/// ※デフォルトSEEDは移植元には存在せず、私が追加したコードとなります。
pub const DEFAULT_SEED: u32 = 5489_u32;

static MAG01: [u32; 2] = [0x0_u32, MATRIX_A];

/// メルセンヌツイスタの実装の本体。
///
/// メルセンヌツイスタをRustに移植してみたもの。正しく移植・実装できているかの保証はできません。
///
/// 移植元のライセンスに関してはソースコード下部に記載してあります。  
///
/// ※フィールドに`[u32; 624]`の固定長配列を持つのでこれをスタックメモリ上で維持したくない場合は[Box]でヒープメモリを使用するなど適宜対処してください。  
///
/// ※初期化に用いるseedやkeyは保持しないため必要な場合は別途管理してください。  
///
/// # Example
///
/// ```
/// use mersenne_twister_rs::MersenneTwister;
/// let seed: u32 = 12_3456_7890;
/// let mut mt = Box::new(MersenneTwister::new(seed));
/// println!("u32 [0,0xffffffff] value: {}", mt.genrand_u32());
/// println!("i32 [0,0x7fffffff] value: {}", mt.genrand_i31());
/// println!("f64 [0,1) value: {}", mt.genrand_real2());
/// ```
#[derive(Debug, Clone)]
pub struct MersenneTwister {
    mt: [u32; N],
    mti: usize,
}

impl std::default::Default for MersenneTwister {
    /// [DEFAULT_SEED]で生成。  
    ///
    /// ※本番環境での使用は推奨しません。  
    ///
    /// ※[DEFAULT_SEED]は移植元には存在せず、私が追加したコードとなります。
    fn default() -> Self {
        MersenneTwister::new(DEFAULT_SEED)
    }
}

impl MersenneTwister {
    /// 指定のseedで生成。  
    ///
    /// seedにはu32型の任意の値を使用できます。  
    pub fn new(seed: u32) -> Self {
        let mut mt = MersenneTwister { mt: [0; N], mti: 0 };
        mt.init(seed);
        mt
    }

    /// 指定のkeyで生成。  
    ///
    /// keyにはu32型の任意の値を列挙したスライスを使用できます。  
    pub fn new_by_array(key: &[u32]) -> Self {
        let mut mt = MersenneTwister { mt: [0; N], mti: 0 };
        mt.init_by_array(key);
        mt
    }

    /// [DEFAULT_SEED]を用いて再初期化します。  
    ///
    /// ※本番環境での使用は推奨しません。  
    ///
    /// ※[DEFAULT_SEED]は移植元には存在せず、私が追加したコードとなります。
    pub fn init_by_default_seed(&mut self) {
        self.init(DEFAULT_SEED);
    }

    /* initializes mt[N] with a seed */
    /// initializes with a seed  
    ///
    /// 指定のseedを用いて再初期化します。
    ///
    /// seedにはu32型の任意の値を使用できます。
    pub fn init(&mut self, seed: u32) {
        self.mti = N;
        let mt = &mut self.mt;
        mt[0] = seed;
        for i in 1..N {
            mt[i] = 1812433253_u32
                .wrapping_mul(mt[i - 1] ^ (mt[i - 1] >> 30))
                .wrapping_add(i as u32);
        }
    }

    /* initialize by an array */
    /// initialize by an array  
    ///
    /// 指定のkeyを用いて再初期化します。
    ///
    /// keyにはu32型の任意の値を列挙したスライスを使用できます。
    pub fn init_by_array(&mut self, key: &[u32]) {
        self.init(19650218_u32);
        let mt = &mut self.mt;
        let mut i: usize = 1;
        let mut j: usize = 0;
        let mut k: usize = key.len().max(N);
        while k > 0 {
            mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)).wrapping_mul(1664525_u32)))
                .wrapping_add(key[j])
                .wrapping_add(j as u32);
            i += 1;
            if i >= N {
                mt[0] = mt[N - 1];
                i = 1;
            }
            j += 1;
            if j >= key.len() {
                j = 0;
            }
            k -= 1;
        }
        k = N - 1;
        while k > 0 {
            mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)).wrapping_mul(1566083941_u32)))
                .wrapping_sub(i as u32);
            i += 1;
            if i >= N {
                mt[0] = mt[N - 1];
                i = 1;
            }
            k -= 1;
        }
        mt[0] = 0x80000000_u32;
    }

    /* generates a random number on [0,0xffffffff]-interval */
    /// generates a random number on \[0,0xffffffff\]-interval  
    ///
    /// 0以上0xFFFF_FFFF以下のu32型の乱数を生成します。
    pub fn genrand_u32(&mut self) -> u32 {
        let mut y: u32;

        if self.mti >= N {
            /* generate N words at one time */
            self.mti = 0;
            let mt = &mut self.mt;
            let mut kk: usize = 0;
            while kk < N - M {
                y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
                mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAG01[(y & 0x1) as usize];
                kk += 1;
            }
            while kk < N - 1 {
                y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
                mt[kk] = mt[kk + M - N] ^ (y >> 1) ^ MAG01[(y & 0x1) as usize];
                kk += 1;
            }
            y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
            mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAG01[(y & 0x1) as usize];
        }

        y = self.mt[self.mti];
        self.mti += 1;

        /* Tempering */
        y ^= y >> 11;
        y ^= (y << 7) & 0x9d2c5680_u32;
        y ^= (y << 15) & 0xefc60000_u32;
        y ^= y >> 18;

        y
    }

    /* generates a random number on [0,0x7fffffff]-interval */
    /// generates a random number on \[0,0x7fffffff\]-interval  
    ///
    /// 0以上0x7FFF_FFFF以下のi32型の乱数を生成します。
    pub fn genrand_i31(&mut self) -> i32 {
        (self.genrand_u32() >> 1) as i32
    }

    /* generates a random number on [0,1]-real-interval */
    /// generates a random number on \[0,1\]-real-interval  
    ///
    /// 0以上1以下のf64型の乱数を生成します。
    pub fn genrand_real1(&mut self) -> f64 {
        (self.genrand_u32() as f64) * (1.0 / 4294967295.0)
        /* divided by 2^32-1 */
    }

    /* generates a random number on [0,1)-real-interval */
    /// generates a random number on \[0,1)-real-interval  
    ///
    /// 0以上1未満のf64型の乱数を生成します。
    pub fn genrand_real2(&mut self) -> f64 {
        (self.genrand_u32() as f64) * (1.0 / 4294967296.0)
        /* divided by 2^32 */
    }

    /* generates a random number on (0,1)-real-interval */
    /// generates a random number on (0,1)-real-interval  
    ///
    /// 1未満のf64型の正数の乱数を生成します。  
    pub fn genrand_real3(&mut self) -> f64 {
        (self.genrand_u32() as f64 + 0.5) * (1.0 / 4294967296.0)
        /* divided by 2^32 */
    }

    /* generates a random number on [0,1) with 53-bit resolution */
    /// generates a random number on \[0,1) with 53-bit resolution
    pub fn genrand_res53(&mut self) -> f64 {
        let a = self.genrand_u32() >> 5;
        let b = self.genrand_u32() >> 6;
        (a as f64 * 67108864.0 + b as f64) * (1.0 / 9007199254740992.0)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        use crate::MersenneTwister;
        use std::fs::{self, File};
        use std::io::Write;

        let mut b: Vec<u8> = Vec::new();

        let init_key: [u32; 4] = [0x123, 0x234, 0x345, 0x456];

        let mut mt = MersenneTwister::new_by_array(&init_key);

        writeln!(&mut b, "1000 outputs of genrand_int32()").unwrap();
        for i in 0..1000 {
            write!(&mut b, "{:10} ", mt.genrand_u32()).unwrap();
            if i % 5 == 4 {
                writeln!(&mut b).unwrap();
            }
        }
        writeln!(&mut b).unwrap();

        writeln!(&mut b, "1000 outputs of genrand_real2()").unwrap();
        for i in 0..1000 {
            write!(&mut b, "{:10.8} ", mt.genrand_real2()).unwrap();
            if i % 5 == 4 {
                writeln!(&mut b).unwrap();
            }
        }

        let original = fs::read("mt19937ar.out").unwrap();

        assert_eq!(b, original);

        File::create("mt19937ar-rs.out")
            .unwrap()
            .write_all(&b)
            .unwrap();
    }
}

/*
 *  疑似乱数生成機(RNG)  移植(Porting)
 *  Information of Original Source
 *  Mersenne Twister with improved initialization (2002)
 *  http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html
 *  http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/mt19937ar.html
 */
// = 移植元ラインセンス (License of Original Source) =======================================================
// ======================================================================
/*
   A C-program for MT19937, with initialization improved 2002/1/26.
   Coded by Takuji Nishimura and Makoto Matsumoto.

   Before using, initialize the state by using init_genrand(seed)
   or init_by_array(init_key, key_length).

   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.

     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.

     3. The names of its contributors may not be used to endorse or promote
        products derived from this software without specific prior written
        permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


   Any feedback is very welcome.
   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
// ======================================================================