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
/*
VAX MTH$RANDOM reimplementation by Radim Kolar <hsn@sendmail.cz> 2024
https://gitlab.com/hsn10/vaxmth

This is free and unencumbered software released into the public domain.
SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#![forbid(unsafe_code)]
#![forbid(missing_docs)]
#![forbid(arithmetic_overflow)]

#![allow(non_snake_case)]

//! LCG69096 / VAX MTH$RANDOM is pseudo random number generator.
//!
//! Generator period is 2^32 for LCG and 2^30 for MCG variant.
//! Generator is named after multiplier coeficient A = 69069.

/**  
  multiplier A coeficient 69069 = 3 * 7 * 11 * 13 * 23

  Used for multiplying seed value.
  This palindromically convoluted multiplier is easy to remember
  and has a nearly cubic lattice for moduli 2 ^ 32, 2 ^ 35, 2 ^ 36.
*/
pub const A: u32 = 69069;
/**
  modulo M coeficient 2^32

  Used for modulo operation final result.
*/
const M: u64 = 0x1_0000_0000;

/** 
  VAX MTH$RANDOM number generator. Its same as LCG69069.

  <https://oeis.org/A096552>
*/
pub struct RANDOM(u32);

impl RANDOM {
   /**
     increment C coeficient 1

     Value is added after mutiplication.
   */
   const C: u32 = 1;
   /** 
     Default seed.

     Default seed in 
   */
   pub const SEED: u32 = 0;

   /**
     Creates new MTH$RANDOM generator with default seed.
   */
   pub fn new() -> Self {
      Self(Self::SEED)
   }
   /**
     Creates new MTH$RANDOM generator with provided seed.
   */
   pub fn seed(seed: u32) -> Self {
      Self(seed)
   }
   /**
     Get next unsigned 32-bit integer from generator.

     Returned value spans entire 32-bit unsigned integer range.
   */
   pub fn next(&mut self) -> u32 {
      self.0 = self.0.wrapping_mul(A).wrapping_add(Self::C);
      self.0
   }
   /**
     Get next double value from generator.

     Returned value is in range zero inclusive to 1.0 exclusive.
   */
   pub fn nextDouble(&mut self) -> f64 {
      self.next() as f64 / M as f64
   }
}

/**
  Multiplicative congruential pseudo-random number generator.

  69069 parameter proposed by George Marsaglia as
  a "candidate for the best of all multipliers".

  Period 2^30

  <https://oeis.org/A096551>
*/
pub struct MCG69069(u32);

impl MCG69069 {
   /**
     Initial MCG seed is 1
   */
   pub const SEED: u32 = 1;

   /**
     Create instance of MCG69069 with initial seed.
   */
   pub fn new() -> Self {
      Self(Self::SEED)
   }

   /**
     Create instance of MCG69069 with specified seed.

     Seed can't be zero.
   */
   pub fn seed(seed: u32) -> Self {
      assert! ( seed !=0, "MCG requires non zero seed." );
      Self(seed)
   }

   /**
     Get next unsigned 32-bit integer from generator.

     Returned value spans entire 32-bit unsigned integer range.
   */
   pub fn next(&mut self) -> u32 {
      self.0 = self.0.wrapping_mul(A);
      self.0
   }
   /**
     Get next double value from generator.

     Returned value is in range zero inclusive to 1.0 exclusive.
   */
   pub fn nextDouble(&mut self) -> f64 {
      self.next() as f64 / M as f64
   }
}

/**
  LCG variant of MCG69069.
*/
pub struct LCG69069(u32);

impl LCG69069 {
   /**
     Initial LCG69069 seed is zero
   */
   pub const SEED: u32 = 0;
   /**
     Increment coeficient for LCG variant is 1
   */
   pub const C: u32 = 1;

   /**
     Create instance of LCG69069 with initial seed.
   */
   pub fn new() -> Self {
      Self(Self::SEED)
   }
   /**
     Create instance of LCG69069 with supplied seed.
   */
   pub fn seed(seed: u32) -> Self {
      Self(seed)
   }
   /**
     Get next unsigned 32-bit integer from generator.

     Returned value spans entire 32-bit unsigned integer range.
   */
   pub fn next(&mut self) -> u32 {
      self.0 = self.0.wrapping_mul(A).wrapping_add(Self::C);
      self.0
   }
   /**
     Get next double value from generator.

     Returned value is in range zero inclusive to 1.0 exclusive.
   */
   pub fn nextDouble(&mut self) -> f64 {
      self.next() as f64 / M as f64
   }
}


#[cfg(test)]
#[path="seq_test.rs"]
mod tests_vax;

#[cfg(test)]
#[path="seq_test_mcg.rs"]
mod tests_mcg;

#[cfg(test)]
#[path="seq_test_lcg.rs"]
mod tests_lcg;

#[cfg(test)]
#[path="period_test.rs"]
mod period;

#[cfg(test)]
#[path="const_test.rs"]
mod consts;

#[cfg(test)]
#[path="assert_test.rs"]
mod assert;