1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.rng.core.source64;
19
20 import java.util.List;
21 import java.util.ArrayList;
22 import org.apache.commons.rng.core.util.NumberFactory;
23
24
25
26
27
28
29
30
31
32
33
34
35 public class TwoCmres extends LongProvider {
36
37 private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
38
39 private static final byte SEED_GUARD = 9;
40
41 private static final Cmres.Factory FACTORY = new Cmres.Factory();
42
43 private final Cmres x;
44
45 private final Cmres y;
46
47 private long xx;
48
49 private long yy;
50
51
52
53
54
55
56
57
58
59 private TwoCmres(int seed,
60 Cmres x,
61 Cmres y) {
62 if (x.equals(y)) {
63 throw new IllegalArgumentException("Subcycle generators must be different");
64 }
65 this.x = x;
66 this.y = y;
67 setSeedInternal(seed);
68 }
69
70
71
72
73
74
75 public TwoCmres(Integer seed) {
76 this(seed, 0, 1);
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public TwoCmres(Integer seed,
92 int i,
93 int j) {
94 this(seed, FACTORY.get(i), FACTORY.get(j));
95 }
96
97
98 @Override
99 public long next() {
100 xx = x.transform(xx);
101 yy = y.transform(yy);
102
103 return xx + yy;
104 }
105
106
107 @Override
108 public String toString() {
109 return super.toString() + " (" + x + " + " + y + ")";
110 }
111
112
113
114
115 public static int numberOfSubcycleGenerators() {
116 return FACTORY.numberOfSubcycleGenerators();
117 }
118
119
120 @Override
121 protected byte[] getStateInternal() {
122 return composeStateInternal(NumberFactory.makeByteArray(new long[] {xx, yy}),
123 super.getStateInternal());
124 }
125
126
127 @Override
128 protected void setStateInternal(byte[] s) {
129 final byte[][] c = splitStateInternal(s, 16);
130
131 final long[] state = NumberFactory.makeLongArray(c[0]);
132 xx = state[0];
133 yy = state[1];
134
135 super.setStateInternal(c[1]);
136 }
137
138
139
140
141 private void setSeedInternal(int seed) {
142
143
144
145
146
147
148
149
150 final int xMax = (seed & 0xffff) + (SEED_GUARD & 0xff);
151 final int yMax = (seed >>> 16) + (SEED_GUARD & 0xff);
152
153 xx = x.getStart();
154 for (int i = xMax; i > 0; i--) {
155 xx = x.transform(xx);
156 }
157
158 yy = y.getStart();
159 for (int i = yMax; i > 0; i--) {
160 yy = y.transform(yy);
161 }
162 }
163
164
165
166
167
168 static class Cmres {
169
170 private static final String SEP = ", ";
171
172 private static final String HEX_FORMAT = "0x%016xL";
173
174 private final int start;
175
176 private final long multiply;
177
178 private final int rotate;
179
180
181
182
183
184
185 Cmres(long multiply,
186 int rotate,
187 int start) {
188 this.multiply = multiply;
189 this.rotate = rotate;
190 this.start = start;
191 }
192
193
194 @Override
195 public String toString() {
196 final String m = String.format((java.util.Locale) null, HEX_FORMAT, multiply);
197 return "Cmres: [" + m + SEP + rotate + SEP + start + "]";
198 }
199
200
201
202
203 public long getMultiply() {
204 return multiply;
205 }
206
207
208
209
210 public int getStart() {
211 return start;
212 }
213
214
215
216
217
218 long transform(long state) {
219 long s = state;
220 s *= multiply;
221 s = Long.rotateLeft(s, rotate);
222 s -= state;
223 return s;
224 }
225
226
227 static class Factory {
228
229 private static final List<Cmres> TABLE = new ArrayList<>();
230
231
232
233
234
235
236
237
238 static {
239 add(0xedce446814d3b3d9L, 33, 0x13b572e7);
240 add(0xc5b3cf786c806df7L, 33, 0x13c8e18a);
241 add(0xdd91bbb8ab9e0e65L, 31, 0x06dd03a6);
242 add(0x7b69342c0790221dL, 31, 0x1646bb8b);
243 add(0x0c72c0d18614c32bL, 33, 0x06014a3d);
244 add(0xd8d98c13bebe26c9L, 33, 0x014e8475);
245 add(0xcb039dc328bbc40fL, 31, 0x008684bd);
246 add(0x858c5ef3c021ed2fL, 32, 0x0dc8d622);
247 add(0x4c8be96bfc23b127L, 33, 0x0b6b20cc);
248 add(0x11eab77f808cf641L, 32, 0x06534421);
249 add(0xbc9bd78810fd28fdL, 31, 0x1d9ba40d);
250 add(0x0f1505c780688cb5L, 33, 0x0b7b7b67);
251 add(0xadc174babc2053afL, 31, 0x267f4197);
252 add(0x900b6b82b31686d9L, 31, 0x023c6985);
253
254 }
255
256
257
258
259 int numberOfSubcycleGenerators() {
260 return TABLE.size();
261 }
262
263
264
265
266
267 Cmres get(int index) {
268 if (index < 0 ||
269 index >= TABLE.size()) {
270 throw new IndexOutOfBoundsException("Out of interval [0, " +
271 (TABLE.size() - 1) + "]");
272 }
273
274 return TABLE.get(index);
275 }
276
277
278
279
280
281
282
283
284 private static void add(long multiply,
285 int rotate,
286 int start) {
287
288
289 checkUnique(TABLE, multiply);
290
291 TABLE.add(new Cmres(multiply, rotate, start));
292 }
293
294
295
296
297
298
299
300
301 static void checkUnique(List<Cmres> table, long multiply) {
302 for (final Cmres sg : table) {
303 if (multiply == sg.getMultiply()) {
304 throw new IllegalStateException(INTERNAL_ERROR_MSG);
305 }
306 }
307 }
308 }
309 }
310 }