SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
LFSR258.java
1/*
2 * Class: LFSR258
3 * Description: 64-bit composite linear feedback shift register proposed by L'Ecuyer
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.rng;
26
27import java.io.Serializable;
28/*
29import umontreal.ssj.util.BitVector;
30import umontreal.ssj.util.BitMatrix;
31*/
32
53public class LFSR258 extends RandomStreamBase {
54
55 private static final long serialVersionUID = 140406L;
56 // La date de modification a l'envers, lire 06/04/2014
57
58 // private static final double NORM = 5.4210108624275221e-20;
59
60 // equivalent a NORM = 1.0 / 0xFFFFFFFFFFFFF800L
61 private static final double NORM = 0.5 / 0x7FFFFFFFFFFFFC00L;
62 private static final double MAX = 0xFFFFFFFFFFFFF800L * NORM + 1.0;
63 // MAX = plus grand double < 1.0
64
65 private static final long GERME = 123456789123456789L;
66
67 private long z0, z1, z2, z3, z4; // l'etat
68
69 // stream and substream variables :
70 private long[] stream;
71 private long[] substream;
72 private static long[] curr_stream = { GERME, GERME, GERME, GERME, GERME };
73
77 public LFSR258() {
78 name = null;
79
80 stream = new long[5];
81 substream = new long[5];
82
83 for (int i = 0; i < 5; i++)
84 stream[i] = curr_stream[i];
85
87
88 // Les operations qui suivent permettent de faire sauter en avant
89 // de 2^200 iterations chacunes des composantes du generateur.
90 // L'etat interne apres le saut est cependant legerement different
91 // de celui apres 2^200 iterations puisqu'il ignore l'etat dans
92 // lequel se retrouvent les premiers bits de chaque composantes,
93 // puisqu'ils sont ignores dans la recurrence. L'etat redevient
94 // identique a ce que l'on aurait avec des iterations normales
95 // apres un appel a nextValue().
96
97 long z, b;
98
99 z = curr_stream[0] & 0xfffffffffffffffeL;
100 b = z ^ (z << 1);
101 z = (b >>> 58) ^ (b >>> 55) ^ (b >>> 46) ^ (b >>> 43) ^ (z << 5) ^ (z << 8) ^ (z << 17) ^ (z << 20);
102 curr_stream[0] = z;
103
104 z = curr_stream[1] & 0xfffffffffffffe00L;
105 b = z ^ (z << 24);
106 z = (b >>> 54) ^ (b >>> 53) ^ (b >>> 52) ^ (b >>> 50) ^ (b >>> 49) ^ (b >>> 48) ^ (b >>> 43) ^ (b >>> 41)
107 ^ (b >>> 38) ^ (b >>> 37) ^ (b >>> 30) ^ (b >>> 25) ^ (b >>> 24) ^ (b >>> 23) ^ (b >>> 19) ^ (b >>> 16)
108 ^ (b >>> 15) ^ (b >>> 14) ^ (b >>> 13) ^ (b >>> 11) ^ (b >>> 8) ^ (b >>> 7) ^ (b >>> 5) ^ (b >>> 3)
109 ^ (z << 0) ^ (z << 2) ^ (z << 3) ^ (z << 6) ^ (z << 7) ^ (z << 8) ^ (z << 9) ^ (z << 10) ^ (z << 11)
110 ^ (z << 12) ^ (z << 13) ^ (z << 14) ^ (z << 16) ^ (z << 18) ^ (z << 19) ^ (z << 21) ^ (z << 25) ^ (z << 30)
111 ^ (z << 31) ^ (z << 32) ^ (z << 36) ^ (z << 39) ^ (z << 40) ^ (z << 41) ^ (z << 42) ^ (z << 44) ^ (z << 47)
112 ^ (z << 48) ^ (z << 50) ^ (z << 52);
113 curr_stream[1] = z;
114
115 z = curr_stream[2] & 0xfffffffffffff000L;
116 b = z ^ (z << 3);
117 z = (b >>> 50) ^ (b >>> 49) ^ (b >>> 46) ^ (b >>> 42) ^ (b >>> 40) ^ (b >>> 39) ^ (b >>> 38) ^ (b >>> 37)
118 ^ (b >>> 36) ^ (b >>> 32) ^ (b >>> 29) ^ (b >>> 28) ^ (b >>> 27) ^ (b >>> 25) ^ (b >>> 23) ^ (b >>> 20)
119 ^ (b >>> 19) ^ (b >>> 15) ^ (b >>> 12) ^ (b >>> 11) ^ (b >>> 2) ^ (z << 1) ^ (z << 2) ^ (z << 3) ^ (z << 6)
120 ^ (z << 10) ^ (z << 12) ^ (z << 13) ^ (z << 14) ^ (z << 15) ^ (z << 16) ^ (z << 20) ^ (z << 23) ^ (z << 24)
121 ^ (z << 25) ^ (z << 27) ^ (z << 29) ^ (z << 32) ^ (z << 33) ^ (z << 37) ^ (z << 40) ^ (z << 41) ^ (z << 50);
122 curr_stream[2] = z;
123
124 z = curr_stream[3] & 0xfffffffffffe0000L;
125 b = z ^ (z << 5);
126 z = (b >>> 46) ^ (b >>> 44) ^ (b >>> 42) ^ (b >>> 41) ^ (b >>> 40) ^ (b >>> 38) ^ (b >>> 36) ^ (b >>> 32)
127 ^ (b >>> 30) ^ (b >>> 25) ^ (b >>> 18) ^ (b >>> 16) ^ (b >>> 15) ^ (b >>> 14) ^ (b >>> 12) ^ (b >>> 11)
128 ^ (b >>> 10) ^ (b >>> 9) ^ (b >>> 8) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (z << 2)
129 ^ (z << 5) ^ (z << 6) ^ (z << 7) ^ (z << 9) ^ (z << 11) ^ (z << 15) ^ (z << 17) ^ (z << 22) ^ (z << 29)
130 ^ (z << 31) ^ (z << 32) ^ (z << 33) ^ (z << 35) ^ (z << 36) ^ (z << 37) ^ (z << 38) ^ (z << 39) ^ (z << 41)
131 ^ (z << 42) ^ (z << 43) ^ (z << 44) ^ (z << 45);
132 curr_stream[3] = z;
133
134 z = curr_stream[4] & 0xffffffffff800000L;
135 b = z ^ (z << 3);
136 z = (b >>> 40) ^ (b >>> 29) ^ (b >>> 10) ^ (z << 1) ^ (z << 12) ^ (z << 31);
137 curr_stream[4] = z;
138
139 }
140
146 public LFSR258(String name) {
147 this();
148 this.name = name;
149 }
150
164 public static void setPackageSeed(long seed[]) {
165 checkSeed(seed);
166 for (int i = 0; i < 5; i++)
167 curr_stream[i] = seed[i];
168 }
169
170 private static void checkSeed(long seed[]) {
171 if (seed.length < 5)
172 throw new IllegalArgumentException("Seed must contain 5 values");
173 if ((seed[0] >= 0 && seed[0] < 2) || (seed[1] >= 0 && seed[1] < 512) || (seed[2] >= 0 && seed[2] < 4096)
174 || (seed[3] >= 0 && seed[3] < 131072) || (seed[4] >= 0 && seed[4] < 8388608))
175 throw new IllegalArgumentException(
176 "The seed elements must be either negative or greater than 1, 511, 4095, 131071 and 8388607 respectively");
177 }
178
191 public void setSeed(long seed[]) {
192 checkSeed(seed);
193 for (int i = 0; i < 5; i++)
194 stream[i] = seed[i];
196 }
197
204 public long[] getState() {
205 return new long[] { z0, z1, z2, z3, z4 };
206 }
207
213 public LFSR258 clone() {
214 LFSR258 retour = null;
215 retour = (LFSR258) super.clone();
216 retour.stream = new long[5];
217 retour.substream = new long[5];
218 for (int i = 0; i < 5; i++) {
219 retour.substream[i] = substream[i];
220 retour.stream[i] = stream[i];
221 }
222 return retour;
223 }
224
225 public void resetStartStream() {
226 for (int i = 0; i < 5; i++)
227 substream[i] = stream[i];
229 }
230
231 public void resetStartSubstream() {
232 z0 = substream[0];
233 z1 = substream[1];
234 z2 = substream[2];
235 z3 = substream[3];
236 z4 = substream[4];
237 }
238
239 public void resetNextSubstream() {
240 // Les operations qui suivent permettent de faire sauter en avant
241 // de 2^100 iterations chacunes des composantes du generateur.
242 // L'etat interne apres le saut est cependant legerement different
243 // de celui apres 2^100 iterations puisqu'il ignore l'etat dans
244 // lequel se retrouvent les premiers bits de chaque composantes,
245 // puisqu'ils sont ignores dans la recurrence. L'etat redevient
246 // identique a ce que l'on aurait avec des iterations normales
247 // apres un appel a nextValue().
248
249 long z, b;
250
251 z = substream[0] & 0xfffffffffffffffeL;
252 b = z ^ (z << 1);
253 z = (b >>> 61) ^ (b >>> 59) ^ (b >>> 58) ^ (b >>> 57) ^ (b >>> 51) ^ (b >>> 47) ^ (b >>> 46) ^ (b >>> 45)
254 ^ (b >>> 43) ^ (b >>> 39) ^ (b >>> 30) ^ (b >>> 29) ^ (b >>> 23) ^ (b >>> 15) ^ (z << 2) ^ (z << 4)
255 ^ (z << 5) ^ (z << 6) ^ (z << 12) ^ (z << 16) ^ (z << 17) ^ (z << 18) ^ (z << 20) ^ (z << 24) ^ (z << 33)
256 ^ (z << 34) ^ (z << 40) ^ (z << 48);
257 substream[0] = z;
258
259 z = substream[1] & 0xfffffffffffffe00L;
260 b = z ^ (z << 24);
261 z = (b >>> 52) ^ (b >>> 50) ^ (b >>> 49) ^ (b >>> 46) ^ (b >>> 43) ^ (b >>> 40) ^ (b >>> 37) ^ (b >>> 34)
262 ^ (b >>> 30) ^ (b >>> 28) ^ (b >>> 26) ^ (b >>> 25) ^ (b >>> 23) ^ (b >>> 21) ^ (b >>> 20) ^ (b >>> 19)
263 ^ (b >>> 17) ^ (b >>> 15) ^ (b >>> 13) ^ (b >>> 12) ^ (b >>> 10) ^ (b >>> 8) ^ (b >>> 7) ^ (b >>> 6)
264 ^ (b >>> 2) ^ (z << 1) ^ (z << 4) ^ (z << 6) ^ (z << 7) ^ (z << 11) ^ (z << 14) ^ (z << 15) ^ (z << 16)
265 ^ (z << 17) ^ (z << 21) ^ (z << 22) ^ (z << 25) ^ (z << 27) ^ (z << 29) ^ (z << 30) ^ (z << 32) ^ (z << 34)
266 ^ (z << 35) ^ (z << 36) ^ (z << 38) ^ (z << 40) ^ (z << 42) ^ (z << 43) ^ (z << 45) ^ (z << 47) ^ (z << 48)
267 ^ (z << 49) ^ (z << 53);
268 substream[1] = z;
269
270 z = substream[2] & 0xfffffffffffff000L;
271 b = z ^ (z << 3);
272 z = (b >>> 49) ^ (b >>> 45) ^ (b >>> 41) ^ (b >>> 40) ^ (b >>> 32) ^ (b >>> 27) ^ (b >>> 23) ^ (b >>> 14)
273 ^ (b >>> 1) ^ (z << 2) ^ (z << 3) ^ (z << 7) ^ (z << 11) ^ (z << 12) ^ (z << 20) ^ (z << 25) ^ (z << 29)
274 ^ (z << 38) ^ (z << 51);
275 substream[2] = z;
276
277 z = substream[3] & 0xfffffffffffe0000L;
278 b = z ^ (z << 5);
279 z = (b >>> 45) ^ (b >>> 32) ^ (b >>> 27) ^ (b >>> 22) ^ (b >>> 17) ^ (b >>> 13) ^ (b >>> 12) ^ (b >>> 7)
280 ^ (b >>> 3) ^ (b >>> 2) ^ (z << 3) ^ (z << 15) ^ (z << 20) ^ (z << 25) ^ (z << 30) ^ (z << 34) ^ (z << 35)
281 ^ (z << 40) ^ (z << 44) ^ (z << 45);
282 substream[3] = z;
283
284 z = substream[4] & 0xffffffffff800000L;
285 b = z ^ (z << 3);
286 z = (b >>> 40) ^ (b >>> 39) ^ (b >>> 38) ^ (b >>> 37) ^ (b >>> 35) ^ (b >>> 34) ^ (b >>> 31) ^ (b >>> 30)
287 ^ (b >>> 29) ^ (b >>> 28) ^ (b >>> 27) ^ (b >>> 26) ^ (b >>> 24) ^ (b >>> 23) ^ (b >>> 21) ^ (b >>> 20)
288 ^ (b >>> 18) ^ (b >>> 15) ^ (b >>> 12) ^ (b >>> 10) ^ (b >>> 9) ^ (b >>> 7) ^ (b >>> 6) ^ (b >>> 5)
289 ^ (b >>> 4) ^ (b >>> 3) ^ (z << 1) ^ (z << 2) ^ (z << 3) ^ (z << 4) ^ (z << 6) ^ (z << 7) ^ (z << 10)
290 ^ (z << 11) ^ (z << 12) ^ (z << 13) ^ (z << 14) ^ (z << 15) ^ (z << 17) ^ (z << 18) ^ (z << 20) ^ (z << 21)
291 ^ (z << 23) ^ (z << 26) ^ (z << 29) ^ (z << 31) ^ (z << 32) ^ (z << 34) ^ (z << 35) ^ (z << 36) ^ (z << 37)
292 ^ (z << 38);
293 substream[4] = z;
294
296 }
297
298 public String toString() {
299 if (name == null)
300 return "The state of the LFSR258 is: " + z0 + "L, " + z1 + "L, " + z2 + "L, " + z3 + "L, " + z4 + "L";
301 else
302 return "The state of " + name + " is: " + z0 + "L, " + z1 + "L, " + z2 + "L, " + z3 + "L, " + z4 + "L";
303 }
304
305 private long nextNumber() {
306 long b;
307 b = (((z0 << 1) ^ z0) >>> 53);
308 z0 = (((z0 & 0xFFFFFFFFFFFFFFFEL) << 10) ^ b);
309 b = (((z1 << 24) ^ z1) >>> 50);
310 z1 = (((z1 & 0xFFFFFFFFFFFFFE00L) << 5) ^ b);
311 b = (((z2 << 3) ^ z2) >>> 23);
312 z2 = (((z2 & 0xFFFFFFFFFFFFF000L) << 29) ^ b);
313 b = (((z3 << 5) ^ z3) >>> 24);
314 z3 = (((z3 & 0xFFFFFFFFFFFE0000L) << 23) ^ b);
315 b = (((z4 << 3) ^ z4) >>> 33);
316 z4 = (((z4 & 0xFFFFFFFFFF800000L) << 8) ^ b);
317
318 return (z0 ^ z1 ^ z2 ^ z3 ^ z4);
319 }
320
321 protected double nextValue() {
322
323 long res = nextNumber();
324 if (res <= 0)
325 return (res * NORM + MAX);
326 else
327 return res * NORM;
328 }
329
330 public int nextInt(int i, int j) {
331 if (i > j)
332 throw new IllegalArgumentException(i + " is larger than " + j + ".");
333 long d = j - i + 1;
334 long q = 0x4000000000000000L / d;
335 long r = 0x4000000000000000L % d;
336 long res;
337
338 do {
339 res = nextNumber() >>> 2;
340 } while (res >= 0x4000000000000000L - r);
341
342 return i + (int) (res / q);
343 }
344
345 /*
346 * Methodes qui permettent de generer les series de shifts des methodes de sauts
347 * en avant.
348 *
349 *
350 * Preuve que la fonction resultante est bien equivalente a la matrice fournie :
351 *
352 * Soit M la matrice de transition pour une iteration simple du Tausworthe d'une
353 * seule composante. (Il est a noter que chaque appel de nextValue fait s
354 * iterations simples pour chaque composantes.)
355 *
356 * On prend I la matrice identite. (I = M^0) Chaque colonne de I represente un
357 * vecteur d'etat pour le generateur. Puisque les (64 - k) bits les moins
358 * significatifs du vecteur d'etat ne sont pas repris par la recurrence a long
359 * terme, c'est-a-dire que la correlation entre leurs valeurs initiales et la
360 * valeur de l'etat (64 - k) iterations simples plus loin est nulle. Donc, a
361 * partir de M^(64 - k), les (64 - k) premieres colonnes de la matrice sont
362 * nulles. Puisque l'on traite qu'avec de tres larges exposants, on peut
363 * supposer que ces colonnes sont nulles, ce qui est equivalent a mettre a 0 les
364 * (64 - k) premiers bits.
365 *
366 * Les colonnes qui suivent dans I, jusqu'aux q dernieres, sont toutes a une
367 * iteration simple d'ecart. Lorsque la matrice I va etre multipliee un certain
368 * nombre de fois par M pour donner M^x, puisque cette operation est equivalente
369 * a faire x iterations simples, ces colonnes resteront a une iteration simple
370 * d'ecart. Puisque l'effet d'une iteration simple consiste simplement de faire
371 * un shift deplacant tous les bits d'une position ainsi que de remplir le bit
372 * vide ainsi cree par une nouvelle valeur, alors les differentes colonnes ne
373 * different que ce shift et leurs extremites. La consequence est que, pour ces
374 * colonnes, tous les bits sur la meme diagonale sont egaux. Il suffit alors de
375 * prendre les valeurs aux debuts des diagonales (dernieres rangee et colonne)
376 * et d'en ressortir les shifts puisqu'un shift est equivalent a une translation
377 * des bits de la matrice identite, donc equivalent a une diagonale dans la
378 * matrice.
379 *
380 * Le meme argument peut etre applique aux q dernieres colonnes de la matrice.
381 * Il y a cependant un fracture entre la q-ieme derniere colonne et la
382 * (q+1)-ieme derniere. Cet ecart vient du fait que, dans I, ces deux colonnes
383 * ne sont pas a une iteration simple d'ecart. Puisque la recurrence qui definit
384 * l'iteration simple est x_n = x_(n-(k-q)) ^ x_(n-k), le nouveau bit qui
385 * s'ajoute au debut de la partie significative (k premiers bits) du vecteur
386 * d'etat est la somme binaire du dernier bit et de (q+1)-ieme dernier bit.
387 * Donc, la (q+1)-ieme derniere colonne est equivalente a la combinaison
388 * lineaire de la derniere et du resultat d'une iteration simple sur la q-ieme
389 * derniere colonne. La consequence est premierement que toutes diagonales (donc
390 * shift) partant de la derniere colonne continue apres la (q+1)-ieme colonne.
391 * Secondement, pour chacune de ces diagonales, une autre diagonale commence a
392 * la meme rangee, mais a la (q+1)-ieme colonne, ce qui est equivalent a un
393 * autre shift, mais avec un masque pour couper les q derniers bits du shift. La
394 * combinaison de ces deux diagonales est b = z ^ (z << q).
395 *
396 *
397 *
398 * private static void analyseMat(BitMatrix bm, int decal, int signif) { //note
399 * : decal = q, signif = k (selon la notation de l'article)
400 *
401 * System.out.println("z = z & 0x" + Long.toHexString(-1 << (64 - signif)) +
402 * "L;"); System.out.println("b = z ^ (z << " + decal + ");");
403 *
404 * StringBuffer sb = new StringBuffer("z ="); for(int i = (64 - signif); i < 63;
405 * i++) if(bm.getBool(i, 63)) sb.append(" (b >>> " + (63 - i) + ") ^");
406 *
407 * for(int i = 0; i < 64; i++) if(bm.getBool(63, 63 - i)) sb.append(" (z << " +
408 * i + ") ^"); sb.setCharAt(sb.length() - 1, ';');
409 *
410 *
411 * System.out.println(sb); }
412 *
413 *
414 * public static void main(String[] args) { BitMatrix bm; BitVector[] bv = new
415 * BitVector[64]; LFSR258 gen = new LFSR258();
416 *
417 * for(int i = 0; i < 64; i++) { gen.z0 = 1L << i; gen.nextValue(); bv[i] = new
418 * BitVector(new int[]{(int)gen.z0, (int)(gen.z0 >>> 32)}); }
419 *
420 * bm = (new BitMatrix(bv)).transpose();
421 *
422 * int W = 100; int Z = 200;
423 *
424 * BitMatrix bmPw = bm.power2e(W); BitMatrix bmPz = bm.power2e(Z);
425 *
426 * analyseMat(bmPw, 1, 63); analyseMat(bmPz, 1, 63); }
427 */
428
429}
double nextValue()
This method should return the next random number (between 0 and 1) from the current stream.
Definition LFSR258.java:321
void resetStartStream()
Reinitializes the stream to its initial state : and are set to .
Definition LFSR258.java:225
void resetNextSubstream()
Reinitializes the stream to the beginning of its next substream:
Definition LFSR258.java:239
void resetStartSubstream()
Reinitializes the stream to the beginning of its current substream:
Definition LFSR258.java:231
long[] getState()
Returns the current state of the stream, represented as an array of five integers.
Definition LFSR258.java:204
int nextInt(int i, int j)
Calls nextDouble once to create one integer between i and j.
Definition LFSR258.java:330
static void setPackageSeed(long seed[])
Sets the initial seed for the class LFSR258 to the five integers of array seed[0.....
Definition LFSR258.java:164
LFSR258(String name)
Constructs a new stream with the identifier name.
Definition LFSR258.java:146
LFSR258 clone()
Clones the current generator and return its copy.
Definition LFSR258.java:213
String toString()
Returns a string containing the current state of this stream.
Definition LFSR258.java:298
LFSR258()
Constructs a new stream.
Definition LFSR258.java:77
void setSeed(long seed[])
This method is discouraged for normal use.
Definition LFSR258.java:191
This class provides a convenient foundation on which RNGs can be built.