1
2
3
4
5
6 package io.github.olyutorskii.aletojio.rng.mwc;
7
8 import io.github.olyutorskii.aletojio.rng.RndInt32;
9 import java.util.Objects;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 public class Mwc implements RndInt32 {
29
30 private static final int DEF_RECORDS = 1038;
31 private static final long DEF_MULTIPLIER = 611373678L;
32 private static final long DEF_DIVISOR = 1L << 32;
33
34 private static final int INIT_OLDEST = 0x0000_0001;
35 private static final int INIT_CARRY = 1;
36
37 private static final String ERRMSG_SMALLLEN = "too short records length";
38 private static final String ERRMSG_SMALLMUL = "too small multiplier";
39 private static final String ERRMSG_SMALLDIV = "too small divisor";
40 private static final String ERRMSG_SEEDLEN = "unmatch seeds length";
41
42
43 private final long mul;
44 private final long div;
45
46 private final int[] records;
47 private final int length;
48
49 private int index;
50
51 private long carry;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public Mwc(int recLen, long mulArg, long divArg) throws IllegalArgumentException {
72 super();
73
74 if (recLen < 1) {
75 throw new IllegalArgumentException(ERRMSG_SMALLLEN);
76 }
77 if (mulArg < 2L) {
78 throw new IllegalArgumentException(ERRMSG_SMALLMUL);
79 }
80 if (divArg < 2L) {
81 throw new IllegalArgumentException(ERRMSG_SMALLDIV);
82 }
83
84 this.records = new int[recLen];
85 this.length = this.records.length;
86
87 this.index = 0;
88 this.records[this.index] = INIT_OLDEST;
89
90 this.mul = mulArg;
91 this.div = divArg;
92 this.carry = INIT_CARRY;
93
94 return;
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public Mwc(int recLen, long mulArg) throws IllegalArgumentException {
112 this(recLen, mulArg, DEF_DIVISOR);
113 return;
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public Mwc() throws IllegalArgumentException {
134 this(DEF_RECORDS, DEF_MULTIPLIER);
135 return;
136 }
137
138
139
140
141
142
143
144 public int getRecords() {
145 return this.length;
146 }
147
148
149
150
151
152
153 public long getCarry() {
154 return this.carry;
155 }
156
157
158
159
160
161
162 public void setCarry(long lVal) {
163 this.carry = lVal;
164 return;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178 public void setSeeds(int... seeds)
179 throws NullPointerException, IllegalArgumentException {
180 Objects.requireNonNull(seeds);
181
182 if (seeds.length != this.length) {
183 throw new IllegalArgumentException(ERRMSG_SEEDLEN);
184 }
185
186 System.arraycopy(seeds, 0, this.records, 0, this.length);
187
188
189 this.index = 0;
190
191 return;
192
193 }
194
195
196
197
198
199
200
201
202 protected int getOldest() {
203
204
205 int result = this.records[this.index];
206 return result;
207 }
208
209
210
211
212
213
214
215
216 protected void pushLatest(int iVal) {
217
218
219 this.records[this.index++] = iVal;
220 if (this.index >= this.length) {
221 this.index = 0;
222 }
223 return;
224 }
225
226
227
228
229
230
231
232
233
234 protected long funcTval(long oldest, long lastCarry) {
235 long result = this.mul * oldest + lastCarry;
236 return result;
237 }
238
239
240
241
242
243
244
245 protected int funcRndFromTval(long tVal) {
246
247
248 long lVal = tVal % this.div;
249 int result = (int) lVal;
250 return result;
251 }
252
253
254
255
256
257
258
259 protected long funcCarryFromTval(long tVal) {
260
261
262 long result = tVal / this.div;
263 return result;
264 }
265
266
267
268
269
270
271 @Override
272 public int nextInt32() {
273 long oldest = getOldest();
274 long lastCarry = this.carry;
275
276 long tVal = funcTval(oldest, lastCarry);
277
278 int latest = funcRndFromTval(tVal);
279 long newCarry = funcCarryFromTval(tVal);
280
281 pushLatest(latest);
282 this.carry = newCarry;
283
284 return latest;
285 }
286
287 }