View Javadoc
1   //******************************************************************************
2   //
3   // File:    Random.java
4   // Package: edu.rit.util
5   // Unit:    Class edu.rit.util.Random
6   //
7   // This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.util;
41  
42  import java.io.Serial;
43  import java.io.Serializable;
44  import java.lang.reflect.Constructor;
45  
46  /**
47   * Class Random is the abstract base class for a pseudorandom number generator
48   * (PRNG) designed for use in parallel scientific programming. It differs from
49   * class java.util.Random in the following ways:
50   * <UL>
51   * <LI>
52   * Instances can be created by calling a static factory method. The factory
53   * method can take the name of a subclass as an argument and return an instance
54   * of that subclass of class Random. This makes it easier to write a program
55   * that can substitute a different PRNG algorithm at run time. Class {@linkplain
56   * DefaultRandom} provides a default PRNG algorithm.
57   * <BR>&nbsp;
58   * <LI>
59   * Whereas class java.util.Random generates 48-bit numbers under the hood, class
60   * Random generates 64-bit numbers. This makes class Random faster than class
61   * java.util.Random for some operations, notably the <code>nextDouble()</code>
62   * method.
63   * <BR>&nbsp;
64   * <LI>
65   * Whereas the PRNG algorithm in class java.util.Random has a period of about
66   * 2<SUP>48</SUP>, the default PRNG algorithm in class {@linkplain
67   * DefaultRandom} has a period of about 2<SUP>64</SUP>. This lets a parallel
68   * program scale up to larger problem sizes without exhausting the PRNG's
69   * period.
70   * <BR>&nbsp;
71   * <LI>
72   * To support the <I>leapfrogging</I> and <I>sequence splitting</I> techniques
73   * for generating pseudorandom numbers in multiple parallel threads or
74   * processes, class Random includes methods for skipping ahead in the sequence
75   * of generated numbers, without having to generate all the intermediate
76   * numbers.
77   * <BR>&nbsp;
78   * <LI>
79   * To avoid unnecessary thread synchronization overhead, class Random is not
80   * multiple thread safe. It assumes that the surrounding program ensures that
81   * only one thread at a time calls methods on an instance.
82   * </UL>
83   * <P>
84   * Each method for generating a number comes in two versions; for example:
85   * <PRE>
86   *     public double nextDouble();
87   *     public double nextDouble (long skip);
88   * </PRE> Calling the second version with an argument <code>skip</code> is
89   * equivalent to calling the first version <code>skip</code> times:
90   * <PRE>
91   *     Random prng1 = Random.getInstance (1234L);
92   *     double x = prng1.nextDouble (1000);
93   *     Random prng2 = Random.getInstance (1234L);
94   *     double y;
95   *     for (int i = 0; i &lt; 1000; ++ i)
96   *         y = prng2.nextDouble();
97   * </PRE> At the end of the above code fragment, <code>x</code> and <code>y</code> will
98   * have the same value. However, calling <code>nextDouble(1000)</code> will
99   * typically be much faster than calling <code>nextDouble()</code> 1000 times.
100  * Conversely,
101  * <code>nextDouble(1)</code> is equivalent to <code>nextDouble()</code>, but the former
102  * will typically be slower than the latter.
103  * <P>
104  * An instance of class Random can be serialized; for example, to checkpoint the
105  * state of the PRNG into a file and restore its state later.
106  * <P>
107  * The design of class Random is inspired in part by Coddington's JAPARA
108  * library. For further information, see P. Coddington and A. Newell, JAPARA --
109  * A Java random number generator library for high-performance computing, in
110  * <I>Proceedings of the 18th IEEE International Parallel and Distributed
111  * Processing Symposium (IPDPS'04),</I> April 26-30, 2004, page 156.
112  *
113  * @author Alan Kaminsky
114  * @version 17-Aug-2009
115  */
116 public abstract class Random
117         implements Serializable {
118 
119     @Serial
120     private static final long serialVersionUID = 1L;
121 
122 // Hidden constants.
123     // 1/2^64, as a float and as a double.
124     private static double D_2_POW_NEG_64;
125     private static float F_2_POW_NEG_64;
126 
127     static {
128         double x = 2.0;
129         x *= x; // 2^2
130         x *= x; // 2^4
131         x *= x; // 2^8
132         x *= x; // 2^16
133         x *= x; // 2^32
134         x *= x; // 2^64
135         D_2_POW_NEG_64 = 1.0 / x;
136         F_2_POW_NEG_64 = (float) D_2_POW_NEG_64;
137     }
138 
139 // Hidden constructors.
140     /**
141      * Construct a new PRNG.
142      */
143     protected Random() {
144     }
145 
146 // Exported operations.
147     /**
148      * Construct a new PRNG with the given seed using the default algorithm.
149      * <P>
150      * If the <code>"pj.prng"</code> Java system property is specified, it gives the
151      * fully-qualified class name of the default PRNG class that the
152      * <code>getInstance()</code> method will construct. Specifying the
153      * <code>"pj.prng"</code> property will substitute a different PRNG algorithm
154      * into a program without needing to recompile.
155      * <P>
156      * If the <code>"pj.prng"</code> Java system property is not specified, the
157      * <code>getInstance()</code> method will return an instance of class
158      * {@linkplain DefaultRandom}.
159      * <P>
160      * You can specify the <code>"pj.prng"</code> property on the Java command line
161      * like this:
162      *
163      * <code>&nbsp;&nbsp;&nbsp;&nbsp;java -Dpj.prng=MyOwnPrngClass . . .</code>
164      * <P>
165      * <I>Note:</I> Depending on the PRNG algorithm, certain seed values may not
166      * be allowed. See the PRNG algorithm subclass for further information.
167      *
168      * @param seed Seed.
169      * @exception IllegalArgumentException (unchecked exception) Thrown if the
170      * PRNG algorithm does not allow the given seed value.
171      * @exception TypeNotPresentException (unchecked exception) Thrown if a PRNG
172      * instance could not be constructed. The chained exception gives further
173      * information about the problem.
174      * @return a {@link edu.rit.util.Random} object.
175      */
176     public static Random getInstance(long seed) {
177         String algorithm = System.getProperty("pj.prng");
178         return algorithm == null
179                 ? new DefaultRandom(seed)
180                 : getInstance(seed, algorithm);
181     }
182 
183     /**
184      * Construct a new PRNG with the given seed using the given algorithm.
185      * <P>
186      * <I>Note:</I> Depending on the PRNG algorithm, certain seed values may not
187      * be allowed. See the PRNG algorithm subclass for further information.
188      *
189      * @param seed Seed.
190      * @param algorithm Fully-qualified name of the class to construct. This
191      * must be a subclass of class Random.
192      * @exception IllegalArgumentException (unchecked exception) Thrown if the
193      * PRNG algorithm does not allow the given seed value.
194      * @exception TypeNotPresentException (unchecked exception) Thrown if a PRNG
195      * instance could not be constructed. The chained exception gives further
196      * information about the problem.
197      * @return a {@link edu.rit.util.Random} object.
198      */
199     public static Random getInstance(long seed,
200             String algorithm) {
201         try {
202             Class<?> cl = Class.forName(algorithm);
203             Constructor<?> ctor = cl.getConstructor(Long.TYPE);
204             return (Random) ctor.newInstance(seed);
205         } catch (Exception exc) {
206             throw new TypeNotPresentException(algorithm, exc);
207         }
208     }
209 
210     /**
211      * Set this PRNG's seed.
212      * <P>
213      * <I>Note:</I> Depending on the PRNG algorithm, certain seed values may not
214      * be allowed. See the PRNG algorithm subclass for further information.
215      *
216      * @param seed Seed.
217      * @exception IllegalArgumentException (unchecked exception) Thrown if the
218      * PRNG algorithm does not allow the given seed value.
219      */
220     public abstract void setSeed(long seed);
221 
222     /**
223      * Skip one position ahead in this PRNG's sequence.
224      */
225     public void skip() {
226         next();
227     }
228 
229     /**
230      * Skip the given number of positions ahead in this PRNG's sequence. If
231      * <code>skip</code> &lt;= 0, the <code>skip()</code> method does nothing.
232      *
233      * @param skip Number of positions to skip.
234      */
235     public void skip(long skip) {
236         if (skip > 0L) {
237             next(skip);
238         }
239     }
240 
241     /**
242      * Return the Boolean value from the next pseudorandom value in this PRNG's
243      * sequence. With a probability of 0.5 <code>true</code> is returned, with a
244      * probability of 0.5 <code>false</code> is returned.
245      *
246      * @return Boolean value.
247      */
248     public boolean nextBoolean() {
249         // Use the high-order (sign) bit of the 64-bit random value.
250         return next() >= 0L;
251     }
252 
253     /**
254      * Return the Boolean value from the pseudorandom value the given number of
255      * positions ahead in this PRNG's sequence. With a probability of 0.5
256      * <code>true</code> is returned, with a probability of 0.5 <code>false</code> is
257      * returned.
258      *
259      * @param skip Number of positions to skip.
260      * @return Boolean value.
261      * @exception IllegalArgumentException (unchecked exception) Thrown if
262      * <code>skip</code> &lt;= 0.
263      */
264     public boolean nextBoolean(long skip) {
265         if (skip <= 0) {
266             throw new IllegalArgumentException("Random.nextBoolean(): skip = " + skip + " illegal");
267         }
268 
269         // Use the high-order (sign) bit of the 64-bit random value.
270         return next(skip) >= 0L;
271     }
272 
273     /**
274      * Return the byte value from the next pseudorandom value in this PRNG's
275      * sequence. Each value in the range &minus;128 through 127 is returned with
276      * a probability of 1/2<SUP>8</SUP>.
277      *
278      * @return Byte value in the range &minus;128 through 127 inclusive.
279      */
280     public byte nextByte() {
281         return (byte) next();
282     }
283 
284     /**
285      * Return the byte value from the next pseudorandom value the given number
286      * of positions ahead in this PRNG's sequence. Each value in the range
287      * &minus;128 through 127 is returned with a probability of 1/2<SUP>8</SUP>.
288      *
289      * @param skip Number of positions to skip.
290      * @return Byte value in the range &minus;128 through 127 inclusive.
291      * @exception IllegalArgumentException (unchecked exception) Thrown if
292      * <code>skip</code> &lt;= 0.
293      */
294     public byte nextByte(long skip) {
295         if (skip <= 0) {
296             throw new IllegalArgumentException("Random.nextByte(): skip = " + skip + " illegal");
297         }
298         return (byte) next(skip);
299     }
300 
301     /**
302      * Return the unsigned byte value from the next pseudorandom value in this
303      * PRNG's sequence. Each value in the range 0 through 255 is returned with a
304      * probability of 1/2<SUP>8</SUP>.
305      *
306      * @return Unsigned byte value (as an <code>int</code>) in the range 0 through
307      * 255 inclusive.
308      */
309     public int nextUnsignedByte() {
310         return (int) (next() & 0xFFL);
311     }
312 
313     /**
314      * Return the unsigned byte value from the next pseudorandom value the given
315      * number of positions ahead in this PRNG's sequence. Each value in the
316      * range 0 through 255 is returned with a probability of 1/2<SUP>8</SUP>.
317      *
318      * @param skip Number of positions to skip.
319      * @return Unsigned byte value (as an <code>int</code>) in the range 0 through
320      * 255 inclusive.
321      * @exception IllegalArgumentException (unchecked exception) Thrown if
322      * <code>skip</code> &lt;= 0.
323      */
324     public int nextUnsignedByte(long skip) {
325         if (skip <= 0) {
326             throw new IllegalArgumentException("Random.nextUnsignedByte(): skip = " + skip + " illegal");
327         }
328         return (int) (next(skip) & 0xFFL);
329     }
330 
331     /**
332      * Return the character value from the next pseudorandom value in this
333      * PRNG's sequence. Each value in the range <code>'&#92;u0000'</code> through
334      * <code>'&#92;uFFFF'</code> is returned with a probability of 1/2<SUP>16</SUP>.
335      *
336      * @return Character value in the range <code>'&#92;u0000'</code> through
337      * <code>'&#92;uFFFF'</code> inclusive.
338      */
339     public char nextCharacter() {
340         return (char) next();
341     }
342 
343     /**
344      * Return the character value from the next pseudorandom value the given
345      * number of positions ahead in this PRNG's sequence. Each value in the
346      * range <code>'&#92;u0000'</code> through <code>'&#92;uFFFF'</code> is returned
347      * with a probability of 1/2<SUP>16</SUP>.
348      *
349      * @param skip Number of positions to skip.
350      * @return Character value in the range <code>'&#92;u0000'</code> through
351      * <code>'&#92;uFFFF'</code> inclusive.
352      * @exception IllegalArgumentException (unchecked exception) Thrown if
353      * <code>skip</code> &lt;= 0.
354      */
355     public int nextCharacter(long skip) {
356         if (skip <= 0) {
357             throw new IllegalArgumentException("Random.nextCharacter(): skip = " + skip + " illegal");
358         }
359         return (char) next(skip);
360     }
361 
362     /**
363      * Return the short value from the next pseudorandom value in this PRNG's
364      * sequence. Each value in the range &minus;32768 through 32767 is returned
365      * with a probability of 1/2<SUP>16</SUP>.
366      *
367      * @return Short value in the range &minus;32768 through 32767 inclusive.
368      */
369     public short nextShort() {
370         return (short) next();
371     }
372 
373     /**
374      * Return the short value from the next pseudorandom value the given number
375      * of positions ahead in this PRNG's sequence. Each value in the range
376      * &minus;32768 through 32767 is returned with a probability of
377      * 1/2<SUP>16</SUP>.
378      *
379      * @param skip Number of positions to skip.
380      * @return Short value in the range &minus;32768 through 32767 inclusive.
381      * @exception IllegalArgumentException (unchecked exception) Thrown if
382      * <code>skip</code> &lt;= 0.
383      */
384     public short nextShort(long skip) {
385         if (skip <= 0) {
386             throw new IllegalArgumentException("Random.nextShort(): skip = " + skip + " illegal");
387         }
388         return (short) next(skip);
389     }
390 
391     /**
392      * Return the unsigned short value from the next pseudorandom value in this
393      * PRNG's sequence. Each value in the range 0 through 65535 is returned with
394      * a probability of 1/2<SUP>16</SUP>.
395      *
396      * @return Unsigned short value (as an <code>int</code>) in the range 0 through
397      * 65535 inclusive.
398      */
399     public int nextUnsignedShort() {
400         return (int) (next() & 0xFFFFL);
401     }
402 
403     /**
404      * Return the unsigned short value from the next pseudorandom value the
405      * given number of positions ahead in this PRNG's sequence. Each value in
406      * the range 0 through 65535 is returned with a probability of
407      * 1/2<SUP>16</SUP>.
408      *
409      * @param skip Number of positions to skip.
410      * @return Unsigned short value (as an <code>int</code>) in the range 0 through
411      * 65535 inclusive.
412      * @exception IllegalArgumentException (unchecked exception) Thrown if
413      * <code>skip</code> &lt;= 0.
414      */
415     public int nextUnsignedShort(long skip) {
416         if (skip <= 0) {
417             throw new IllegalArgumentException("Random.nextUnsignedShort(): skip = " + skip + " illegal");
418         }
419         return (int) (next(skip) & 0xFFFFL);
420     }
421 
422     /**
423      * Return the integer value from the next pseudorandom value in this PRNG's
424      * sequence. Each value in the range &minus;2147483648 through 2147483647 is
425      * returned with a probability of 1/2<SUP>32</SUP>.
426      *
427      * @return Integer value in the range &minus;2147483648 through 2147483647
428      * inclusive.
429      */
430     public int nextInteger() {
431         return (int) next();
432     }
433 
434     /**
435      * Return the integer value from the next pseudorandom value the given
436      * number of positions ahead in this PRNG's sequence. Each value in the
437      * range &minus;2147483648 through 2147483647 is returned with a probability
438      * of 1/2<SUP>32</SUP>.
439      *
440      * @param skip Number of positions to skip.
441      * @return Integer value in the range &minus;2147483648 through 2147483647
442      * inclusive.
443      * @exception IllegalArgumentException (unchecked exception) Thrown if
444      * <code>skip</code> &lt;= 0.
445      */
446     public int nextInteger(long skip) {
447         if (skip <= 0) {
448             throw new IllegalArgumentException("Random.nextInteger(): skip = " + skip + " illegal");
449         }
450         return (int) next(skip);
451     }
452 
453     /**
454      * Return the integer value in the given range from the next pseudorandom
455      * value in this PRNG's sequence. Each value in the range 0 through
456      * <I>N</I>&minus;1 is returned with a probability of 1/<I>N</I>.
457      *
458      * @param n Range of values to return.
459      * @return Integer value in the range 0 through <I>N</I>&minus;1 inclusive.
460      * @exception IllegalArgumentException (unchecked exception) Thrown if
461      * <I>N</I> &lt;= 0.
462      */
463     public int nextInt(int n) {
464         if (n <= 0) {
465             throw new IllegalArgumentException("Random.nextInt(): n = " + n + " illegal");
466         }
467         return (int) Math.floor(nextDouble() * n);
468     }
469 
470     /**
471      * Return the integer value in the given range from the pseudorandom value
472      * the given number of positions ahead in this PRNG's sequence. Each value
473      * in the range 0 through <I>N</I>&minus;1 is returned with a probability of
474      * 1/<I>N</I>.
475      *
476      * @param n Range of values to return.
477      * @param skip Number of positions to skip.
478      * @return Integer value in the range 0 through <I>N</I>&minus;1 inclusive.
479      * @exception IllegalArgumentException (unchecked exception) Thrown if
480      * <I>N</I> &lt;= 0. Thrown if
481      * <code>skip</code> &lt;= 0.
482      */
483     public int nextInt(int n,
484             long skip) {
485         if (n <= 0) {
486             throw new IllegalArgumentException("Random.nextInt(): n = " + n + " illegal");
487         }
488         return (int) Math.floor(nextDouble(skip) * n);
489     }
490 
491     /**
492      * Return the long value from the next pseudorandom value in this PRNG's
493      * sequence. Each value in the range &minus;9223372036854775808 through
494      * 9223372036854775807 is returned with a probability of 1/2<SUP>64</SUP>.
495      *
496      * @return Long value in the range &minus;9223372036854775808 through
497      * 9223372036854775807 inclusive.
498      */
499     public long nextLong() {
500         return next();
501     }
502 
503     /**
504      * Return the long value from the next pseudorandom value the given number
505      * of positions ahead in this PRNG's sequence. Each value in the range
506      * &minus;9223372036854775808 through 9223372036854775807 is returned with a
507      * probability of 1/2<SUP>64</SUP>.
508      *
509      * @param skip Number of positions to skip.
510      * @return Long value in the range &minus;9223372036854775808 through
511      * 9223372036854775807 inclusive.
512      * @exception IllegalArgumentException (unchecked exception) Thrown if
513      * <code>skip</code> &lt;= 0.
514      */
515     public long nextLong(long skip) {
516         if (skip <= 0) {
517             throw new IllegalArgumentException("Random.nextLong(): skip = " + skip + " illegal");
518         }
519         return next(skip);
520     }
521 
522     /**
523      * Return the single precision floating point value from the next
524      * pseudorandom value in this PRNG's sequence. The returned numbers have a
525      * uniform distribution in the range 0.0 (inclusive) to 1.0 (exclusive).
526      *
527      * @return Float value.
528      */
529     public float nextFloat() {
530         // Next random number is in the range -2^63 .. +2^63 - 1.
531         // Divide by 2^64 yielding a number in the range -0.5 .. +0.5.
532         // Add 0.5 yielding a number in the range 0.0 .. 1.0.
533         return (float) (next()) * F_2_POW_NEG_64 + 0.5f;
534     }
535 
536     /**
537      * Return the single precision floating point value from the pseudorandom
538      * value the given number of positions ahead in this PRNG's sequence. The
539      * returned numbers have a uniform distribution in the range 0.0 (inclusive)
540      * to 1.0 (exclusive).
541      *
542      * @param skip Number of positions to skip.
543      * @return Float value.
544      * @exception IllegalArgumentException (unchecked exception) Thrown if
545      * <code>skip</code> &lt;= 0.
546      */
547     public float nextFloat(long skip) {
548         if (skip <= 0) {
549             throw new IllegalArgumentException("Random.nextFloat(): skip = " + skip + " illegal");
550         }
551 
552         // Next random number is in the range -2^63 .. +2^63 - 1.
553         // Divide by 2^64 yielding a number in the range -0.5 .. +0.5.
554         // Add 0.5 yielding a number in the range 0.0 .. 1.0.
555         return (float) (next(skip)) * F_2_POW_NEG_64 + 0.5f;
556     }
557 
558     /**
559      * Return the double precision floating point value from the next
560      * pseudorandom value in this PRNG's sequence. The returned numbers have a
561      * uniform distribution in the range 0.0 (inclusive) to 1.0 (exclusive).
562      *
563      * @return Double value.
564      */
565     public double nextDouble() {
566         // Next random number is in the range -2^63 .. +2^63 - 1.
567         // Divide by 2^64 yielding a number in the range -0.5 .. +0.5.
568         // Add 0.5 yielding a number in the range 0.0 .. 1.0.
569         return (double) (next()) * D_2_POW_NEG_64 + 0.5;
570     }
571 
572     /**
573      * Return the double precision floating point value from the pseudorandom
574      * value the given number of positions ahead in this PRNG's sequence. The
575      * returned numbers have a uniform distribution in the range 0.0 (inclusive)
576      * to 1.0 (exclusive).
577      *
578      * @param skip Number of positions to skip.
579      * @return Double value.
580      * @exception IllegalArgumentException (unchecked exception) Thrown if
581      * <code>skip</code> &lt;= 0.
582      */
583     public double nextDouble(long skip) {
584         if (skip <= 0) {
585             throw new IllegalArgumentException("Random.nextDouble(): skip = " + skip + " illegal");
586         }
587 
588         // Next random number is in the range -2^63 .. +2^63 - 1.
589         // Divide by 2^64 yielding a number in the range -0.5 .. +0.5.
590         // Add 0.5 yielding a number in the range 0.0 .. 1.0.
591         return (double) (next(skip)) * D_2_POW_NEG_64 + 0.5;
592     }
593 
594 // Hidden operations.
595     /**
596      * Return the next 64-bit pseudorandom value in this PRNG's sequence.
597      *
598      * @return Pseudorandom value.
599      */
600     protected abstract long next();
601 
602     /**
603      * Return the 64-bit pseudorandom value the given number of positions ahead
604      * in this PRNG's sequence.
605      *
606      * @param skip Number of positions to skip, assumed to be &gt; 0.
607      * @return Pseudorandom value.
608      */
609     protected abstract long next(long skip);
610 
611 }