View Javadoc
1   /*
2    * License : The MIT License
3    * Copyright(c) 2022 olyutorskii
4    */
5   
6   package io.github.olyutorskii.aletojio.rng.lcg;
7   
8   /**
9    * Factory of Linear congruential generator (LCG) implementations.
10   *
11   * <p>LCG is a commonly used random number generator in the past.
12   *
13   * <p>Recurrence relation sequences : {@code X(n+1) = (X(n) * Mul + Inc) mod Mod}
14   *
15   * <ul>
16   * <li>Mul : Multiplier
17   * <li>Inc : Increment
18   * <li>Mod : Modulus
19   * </ul>
20   *
21   * <p>Provides a random number generator
22   * compatible with the following LCGs.
23   *
24   * <ul>
25   * <li>RANDU :   IBM Scientific Subroutine Library for IBM System/360
26   * <li>MINSTD0 : C++11's minstd_rand0
27   * <li>MINSTD :  C++11's minstd_rand
28   * <li>GLIBC :   glibc rand()
29   * <li>LRAND48 : glibc lrand48()
30   * <li>MRAND48 : glibc mrand48()
31   * </ul>
32   *
33   * <p>mrand48() is compatible with {@link java.util.Random}.
34   * But seed of java.util.Random is scrambled. Try {@link #seedScrambler4M48(long)}
35   *
36   * @see java.util.Random
37   * @see <a href="https://en.wikipedia.org/wiki/Linear_congruential_generator">
38   * Linear congruential generator (Wikipedia)
39   * </a>
40   */
41  public final class LcgFactory {
42  
43      private static final long RANDU_MUL   =           65539L;      // 6544th prime number
44      private static final long RANDU_INC   =               0L;
45      private static final long RANDU_MOD   =      2147483648L;      // 2^31
46  
47      private static final long MINSTD0_MUL =           16807L;      // (7^5)%MINSTD_MOD
48  
49      private static final long MINSTD_MUL  =           48271L;      // (7^1116395447)%MISTD_MOD and 4968th prime number
50      private static final long MINSTD_INC  =               0L;
51      private static final long MINSTD_MOD  =      2147483647L;      // (2^31)-1 and 8th Mersenne prime number
52  
53      private static final long GLIBC_MUL   =      1103515245L;      // ?th prime number
54      private static final long GLIBC_INC   =           12345L;
55      private static final long GLIBC_MOD   =      2147483648L;      // 2^31
56  
57      private static final long MRAND48_MUL =     25214903917L;      // ?th prime number
58      private static final long MRAND48_INC =              11L;
59      private static final long MRAND48_MOD = 281474976710656L;      // 2^48
60  
61      private static final long RANDU_INITSEED   =              1L;
62      private static final long MINSTD_INITSEED  =              1L;
63      private static final long GLIBC_INITSEED   =              1L;
64      private static final long MRAND48_INITSEED = 20017429951246L;
65  
66      private static final long MRAND48_MASK = MRAND48_MOD - 1L;
67  
68      static {
69          assert RANDU_MUL   == 0x00010003L;
70          assert MINSTD0_MUL == 0x000041a7L;
71          assert MINSTD_MUL  == 0x0000bc8fL;
72          assert GLIBC_MUL   == 0x41c64e6dL;
73          assert MRAND48_MUL == 0x05deece66dL;
74  
75          assert MRAND48_INITSEED == 0x1234abcd330eL;
76  
77          assert MRAND48_MASK == 0xffff_ffff_ffffL;
78  
79          new LcgFactory().hashCode();
80      }
81  
82  
83      /**
84       * Hidden constructor.
85       */
86      private LcgFactory() {
87      }
88  
89  
90      /**
91       * Create RANDU compatible random number generator.
92       *
93       * <p>RANDU was included in IBM Scientific Subroutine Library for IBM System/360
94       *
95       * <p>RANDU generates 31bit output without sign.
96       *
97       * @return random number generator
98       * @see <a href="https://en.wikipedia.org/wiki/RANDU">RANDU (Wikipedia)</a>
99       */
100     public static LcgRndInt31 createRandu() {
101         LcgRndInt31 result;
102         result = new LcgRndInt31(RANDU_MUL, RANDU_INC, RANDU_MOD);
103         result.setSeed(RANDU_INITSEED);
104         return result;
105     }
106 
107     /**
108      * Create minstd_rand0() compatible random number generator.
109      *
110      * <p>minstd_rand0() is used in C++11.
111      *
112      * <p>minstd_rand() is better than minstd_rand0(),
113      *
114      * <p>minstd_rand0() generates 31bit output without sign.
115      *
116      * @return random number generator
117      * @see <a href="https://en.wikipedia.org/wiki/Lehmer_random_number_generator">
118      * Lehmer random number generator (Wikipedia)
119      * </a>
120      */
121     public static LcgRndInt31 createMinStd0() {
122         LcgRndInt31 result;
123         result = new LcgRndInt31(MINSTD0_MUL, MINSTD_INC, MINSTD_MOD);
124         result.setSeed(MINSTD_INITSEED);
125         return result;
126     }
127 
128     /**
129      * Create minstd_rand() compatible random number generator.
130      *
131      * <p>minstd_rand() is used in C++11.
132      *
133      * <p>minstd_rand() is better than minstd_rand0(),
134      *
135      * <p>minstd_rand() generates 31bit output without sign.
136      *
137      * @return random number generator
138      * @see <a href="https://en.wikipedia.org/wiki/Lehmer_random_number_generator">
139      * Lehmer random number generator (Wikipedia)
140      * </a>
141      */
142     public static LcgRndInt31 createMinStd() {
143         LcgRndInt31 result;
144         result = new LcgRndInt31(MINSTD_MUL, MINSTD_INC, MINSTD_MOD);
145         result.setSeed(MINSTD_INITSEED);
146         return result;
147     }
148 
149     /**
150      * Create glibc rand() compatible random number generator.
151      *
152      * <p>rand() is used in glibc library.
153      *
154      * <p>rand() generates 31bit output without sign.
155      *
156      * @return random number generator
157      */
158     public static LcgRndInt31 createGlibc() {
159         LcgRndInt31 result;
160         result = new LcgRndInt31(GLIBC_MUL, GLIBC_INC, GLIBC_MOD);
161         result.setSeed(GLIBC_INITSEED);
162         return result;
163     }
164 
165     /**
166      * Create lrand48() compatible random number generator.
167      *
168      * <p>lrand48() is used in Un*x common C-library.
169      *
170      * <p>lrand48() generates 31bit output without sign.
171      * result(31bit) reflects seed[17:47]
172      *
173      * @return random number generator
174      */
175     public static LcgRndInt31 createLrand48() {
176         LcgRndInt31 result;
177         result = new LcgRndInt31(MRAND48_MUL, MRAND48_INC, MRAND48_MOD) {
178             @Override
179             protected int seedToResult() {
180                 long lVal = getSeed() >>> 17;
181                 lVal &= MASK_B31;
182                 int result = (int) lVal;
183                 return result;
184             }
185         };
186 
187         result.setSeed(MRAND48_INITSEED);
188         return result;
189     }
190 
191     /**
192      * Create mrand48() compatible random generator.
193      *
194      * <p>mrand48() is used in Un*x common C-library.
195      *
196      * <p>mrand48() generates 32bit output.
197      *
198      * @return random number generator
199      */
200     public static LcgRndInt32 createMrand48() {
201         LcgRndInt32 result;
202         result = new LcgRndInt32(MRAND48_MUL, MRAND48_INC, MRAND48_MOD);
203         result.setSeed(MRAND48_INITSEED);
204         return result;
205     }
206 
207     /**
208      * Seed scrambler for mrand48().
209      *
210      * <p>Seed of {@link java.util.Random#setSeed(long)} will be converted to seed of mrand48().
211      *
212      * @param seedArg seed of {@link java.util.Random}
213      * @return seed of mrand48()
214      *
215      * @see java.util.Random#setSeed(long)
216      */
217     public static long seedScrambler4M48(long seedArg) {
218         long result = (seedArg ^ MRAND48_MUL) & MRAND48_MASK;
219         return result;
220     }
221 
222 }