1use core::cmp::min;
2
3use crate::TinyMT64;
4
5const TINYMT64_MEXP: usize = 127;
6const TINYMT64_SH0: u64 = 12;
7const TINYMT64_SH1: u64 = 11;
8const TINYMT64_SH8: u64 = 8;
9const TINYMT64_MASK: u64 = 0x7fff_ffff_ffff_ffff_u64;
10const TINYMT64_MUL: f64 = 1.0 / 9_007_199_254_740_992.0;
11const MIN_LOOP: usize = 8;
12
13impl TinyMT64 {
14 pub fn new(status: [u64; 2], mat1: u32, mat2: u32, tmat: u64) -> TinyMT64 {
15 TinyMT64 { status, mat1, mat2, tmat }
16 }
17}
18
19#[inline]
21fn ini_func1(x: u64) -> u64 {
22 (x ^ (x >> 59)).wrapping_mul(2_173_292_883_993_u64)
23}
24
25#[inline]
27fn ini_func2(x: u64) -> u64 {
28 (x ^ (x >> 59)).wrapping_mul(58_885_565_329_898_161_u64)
29}
30
31#[inline]
33fn period_certification(random: &mut TinyMT64) {
34 if random.status[0] & TINYMT64_MASK == 0 && random.status[1] == 0 {
35 random.status[0] = 'T' as u64;
36 random.status[1] = 'M' as u64;
37 }
38}
39
40pub fn tinymt64_init(random: &mut TinyMT64, seed: u64) {
43 random.status[0] = seed ^ ((random.mat1 as u64) << 32);
44 random.status[1] = (random.mat2 as u64) ^ random.tmat;
45 for i in 1..MIN_LOOP {
46 random.status[i & 1] ^= (i as u64).wrapping_add(
47 6_364_136_223_846_793_005_u64
48 .wrapping_mul(random.status[(i - 1) & 1] ^ (random.status[(i - 1) & 1] >> 62)),
49 );
50 }
51 period_certification(random);
52}
53
54pub fn tinymt64_init_by_array(random: &mut TinyMT64, init_key: &[u64]) {
58 let lag: usize = 1;
59 let mid: usize = 1;
60 let size: usize = 4;
61 let key_length: usize = init_key.len();
62
63 let mut st: [u64; 4] = [0, random.mat1 as u64, random.mat2 as u64, random.tmat];
64 let mut count: usize = if key_length + 1 > MIN_LOOP { key_length + 1 } else { MIN_LOOP };
65 let mut r: u64 = ini_func1(st[0] ^ st[mid % size] ^ st[(size - 1) % size]);
66 st[mid % size] += r;
67 r += key_length as u64;
68 st[(mid + lag) % size] += r;
69 st[0] = r;
70 count -= 1;
71 let mut i = 1;
72 let boundary = min(count, key_length);
73 for key in init_key.iter().take(boundary) {
74 r = ini_func1(st[i] ^ st[(i + mid) % size] ^ st[(i + size - 1) % size]);
75 st[(i + mid) % size] = st[(i + mid) % size].wrapping_add(r);
76 r += key + i as u64;
77 st[(i + mid + lag) % size] = st[(i + mid + lag) % size].wrapping_add(r);
78 st[i] = r;
79 i = (i + 1) % size;
80 }
81 for _ in boundary..count {
82 r = ini_func1(st[i] ^ st[(i + mid) % size] ^ st[(i + size - 1) % size]);
83 st[(i + mid) % size] = st[(i + mid) % size].wrapping_add(r);
84 r += i as u64;
85 st[(i + mid + lag) % size] = st[(i + mid + lag) % size].wrapping_add(r);
86 st[i] = r;
87 i = (i + 1) % size;
88 }
89 for _ in 0..size {
90 r = ini_func2(st[i].wrapping_add(st[(i + mid) % size]).wrapping_add(st[(i + size - 1) % size]));
91 st[(i + mid) % size] ^= r;
92 r -= i as u64;
93 st[(i + mid + lag) % size] ^= r;
94 st[i] = r;
95 i = (i + 1) % size;
96 }
97 random.status[0] = st[0] ^ st[1];
98 random.status[1] = st[2] ^ st[3];
99 period_certification(random);
100}
101
102#[inline]
104pub fn tinymt64_get_mexp(_: &TinyMT64) -> usize {
105 TINYMT64_MEXP
106}
107
108#[inline]
113pub fn tinymt64_next_state(random: &mut TinyMT64) {
114 random.status[0] &= TINYMT64_MASK;
115 let mut x: u64 = random.status[0] ^ random.status[1];
116 x ^= x << TINYMT64_SH0;
117 x ^= x >> 32;
118 x ^= x << 32;
119 x ^= x << TINYMT64_SH1;
120 random.status[0] = random.status[1];
121 random.status[1] = x;
122 random.status[0] ^= (-((x & 1) as i64) as u64) & (random.mat1 as u64);
123 random.status[1] ^= (-((x & 1) as i64) as u64) & ((random.mat2 as u64) << 32);
124}
125
126#[inline]
129pub fn tinymt64_temper(random: &TinyMT64) -> u64 {
130 let mut x = random.status[0].wrapping_add(random.status[1]);
133 x ^= random.status[0] >> TINYMT64_SH8;
134 x ^ (-((x & 1) as i64) as u64) & random.tmat
135}
136
137#[inline]
140pub fn tinymt64_temper_conv(random: &TinyMT64) -> f64 {
141 let mut x = random.status[0].wrapping_add(random.status[1]);
144 x ^= random.status[0] >> TINYMT64_SH8;
145 x = ((x ^ ((-((x & 1) as i64) as u64) & random.tmat)) >> 12) | 0x3ff0_0000_0000_0000_u64;
146 f64::from_le_bytes(x.to_le_bytes())
147}
148
149#[inline]
152pub fn tinymt64_temper_conv_open(random: &TinyMT64) -> f64 {
153 let mut x = random.status[0].wrapping_add(random.status[1]);
156 x ^= random.status[0] >> TINYMT64_SH8;
157 x = ((x ^ ((-((x & 1) as i64) as u64) & random.tmat)) >> 12) | 0x3ff0_0000_0000_0001_u64;
158 f64::from_le_bytes(x.to_le_bytes())
159}
160
161#[inline]
164pub fn tinymt64_generate_uint64(random: &mut TinyMT64) -> u64 {
165 tinymt64_next_state(random);
166 tinymt64_temper(random)
167}
168
169#[inline]
173pub fn tinymt64_generate_double(random: &mut TinyMT64) -> f64 {
174 tinymt64_next_state(random);
175 ((tinymt64_temper(random) >> 11) as f64) * TINYMT64_MUL
176}
177
178#[inline]
182pub fn tinymt64_generate_double01(random: &mut TinyMT64) -> f64 {
183 tinymt64_next_state(random);
184 tinymt64_temper_conv(random) - 1.0
185}
186
187#[inline]
191pub fn tinymt64_generate_double12(random: &mut TinyMT64) -> f64 {
192 tinymt64_next_state(random);
193 tinymt64_temper_conv(random)
194}
195
196#[inline]
200pub fn tinymt64_generate_double_oc(random: &mut TinyMT64) -> f64 {
201 tinymt64_next_state(random);
202 2.0 - tinymt64_temper_conv(random)
203}
204
205pub fn tinymt64_generate_double_oo(random: &mut TinyMT64) -> f64 {
209 tinymt64_next_state(random);
210 tinymt64_temper_conv_open(random) - 1.0
211}