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