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 == 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 final long s = NumberFactory.makeLong(0, seed);
150 final int xMax = (int) ((s & 0xffff) + SEED_GUARD);
151 final int yMax = (int) ((s >> 16) + SEED_GUARD);
152
153 if (xMax < 0 ||
154 yMax < 0) {
155 throw new IllegalStateException(INTERNAL_ERROR_MSG);
156 }
157
158 xx = x.getStart();
159 for (int i = xMax; i > 0; i--) {
160 xx = x.transform(xx);
161 }
162
163 yy = y.getStart();
164 for (int i = yMax; i > 0; i--) {
165 yy = y.transform(yy);
166 }
167 }
168
169
170
171
172
173 static class Cmres {
174
175 private static final String SEP = ", ";
176
177 private static final String HEX_FORMAT = "0x%016xL";
178
179 private final int start;
180
181 private final long multiply;
182
183 private final int rotate;
184
185
186
187
188
189
190 Cmres(long multiply,
191 int rotate,
192 int start) {
193 this.multiply = multiply;
194 this.rotate = rotate;
195 this.start = start;
196 }
197
198
199 @Override
200 public String toString() {
201 final String m = String.format((java.util.Locale) null, HEX_FORMAT, multiply);
202 return "Cmres: [" + m + SEP + rotate + SEP + start + "]";
203 }
204
205
206
207
208 public long getMultiply() {
209 return multiply;
210 }
211
212
213
214
215 public int getStart() {
216 return start;
217 }
218
219
220
221
222
223 long transform(long state) {
224 long s = state;
225 s *= multiply;
226 s = rotl(s);
227 s -= state;
228 return s;
229 }
230
231
232
233
234
235 private long rotl(long state) {
236 return (state << rotate) | (state >>> (64 - rotate));
237 }
238
239
240 static class Factory {
241
242 private static final List<Cmres> TABLE = new ArrayList<Cmres>();
243
244
245
246
247
248
249
250
251 static {
252 add(0xedce446814d3b3d9L, 33, 0x13b572e7);
253 add(0xc5b3cf786c806df7L, 33, 0x13c8e18a);
254 add(0xdd91bbb8ab9e0e65L, 31, 0x06dd03a6);
255 add(0x7b69342c0790221dL, 31, 0x1646bb8b);
256 add(0x0c72c0d18614c32bL, 33, 0x06014a3d);
257 add(0xd8d98c13bebe26c9L, 33, 0x014e8475);
258 add(0xcb039dc328bbc40fL, 31, 0x008684bd);
259 add(0x858c5ef3c021ed2fL, 32, 0x0dc8d622);
260 add(0x4c8be96bfc23b127L, 33, 0x0b6b20cc);
261 add(0x11eab77f808cf641L, 32, 0x06534421);
262 add(0xbc9bd78810fd28fdL, 31, 0x1d9ba40d);
263 add(0x0f1505c780688cb5L, 33, 0x0b7b7b67);
264 add(0xadc174babc2053afL, 31, 0x267f4197);
265 add(0x900b6b82b31686d9L, 31, 0x023c6985);
266
267 }
268
269
270
271
272 int numberOfSubcycleGenerators() {
273 return TABLE.size();
274 }
275
276
277
278
279
280 Cmres get(int index) {
281 if (index < 0 ||
282 index >= TABLE.size()) {
283 throw new IndexOutOfBoundsException("Out of interval [0, " +
284 (TABLE.size() - 1) + "]");
285 }
286
287 return TABLE.get(index);
288 }
289
290
291
292
293
294
295
296
297 private static void add(long multiply,
298 int rotate,
299 int start) {
300
301
302 for (Cmres sg : TABLE) {
303 if (multiply == sg.getMultiply()) {
304 throw new IllegalStateException(INTERNAL_ERROR_MSG);
305 }
306 }
307
308 TABLE.add(new Cmres(multiply, rotate, start));
309 }
310 }
311 }
312 }