001    package com.softnetConsult.utils.random;
002    
003    import java.util.Random;
004    
005    
006    /**
007     * Provides a fast pseudorandom number generator by trading off memory for speed.
008     * Objects of this class generate a large number of random numbers when
009     * they are created and reuse them throughout the life-time. For many
010     * applications the repetition effect does not significantly affect the
011     * quality of the random series given that the size of the buffer sufficiently
012     * large. This class is usefull when a time-critical application requires a
013     * very large number of random numbers; a slight delay for the buffer creation
014     * at the start saves a lot of time during the runtime. <br />
015     * Note that the current version of this class accelerates only the generation of
016     * pseudorandom values of types {@code boolean}, {@code double} and {@code int}:
017     * pseudorandom values are pre-generated and cached, pseudorandom values of other
018     * types are generated on the fly by passing the {@code nextXXX()}-calls to the
019     * default Java pseudorandom number generator.
020     * 
021     * <p style="font-size:smaller;">This product includes software developed by the
022     *    <strong>SoftNet-Consult Java Utility Library</strong> project and its contributors.<br />
023     *    (<a href="http://java-tools.sourceforge.net" target="_blank">http://java-tools.sourceforge.net</a>)<br />
024     *    Copyright (c) 2007-2008 SoftNet-Consult.<br />
025     *    Copyright (c) 2007-2008 G. Paperin.<br />
026     *    All rights reserved.
027     * </p>
028     * <p style="font-size:smaller;">File: FastRandom.java<br />
029     *    Library API version: {@value com.softnetConsult.utils.APIProperties#apiVersion}<br />
030     *    Java compliance version: {@value com.softnetConsult.utils.APIProperties#javaComplianceVersion}
031     * </p>
032     * <p style="font-size:smaller;">Redistribution and use in source and binary forms, with or
033     *    without modification, are permitted provided that the following terms and conditions are met:
034     * </p>
035     * <p style="font-size:smaller;">1. Redistributions of source code must retain the above
036     *    acknowledgement of the SoftNet-Consult Java Utility Library project, the above copyright
037     *    notice, this list of conditions and the following disclaimer.<br />
038     *    2. Redistributions in binary form must reproduce the above acknowledgement of the
039     *    SoftNet-Consult Java Utility Library project, the above copyright notice, this list of
040     *    conditions and the following disclaimer in the documentation and/or other materials
041     *    provided with the distribution.<br />
042     *    3. All advertising materials mentioning features or use of this software or any derived
043     *    software must display the following acknowledgement:<br />
044     *    <em>This product includes software developed by the SoftNet-Consult Java Utility Library
045     *    project and its contributors.</em>
046     * </p>
047     * <p style="font-size:smaller;">THIS SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY
048     *    OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
049     *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL
050     *    THE AUTHORS, CONTRIBUTORS OR COPYRIGHT  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
051     *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM, OUT OF OR
052     *    IN CONNECTION WITH THE SOFTWARE OR THE USE OR  OTHER DEALINGS IN THE SOFTWARE.
053     * </p> 
054     * @author Greg Paperin (<a href="http://www.paperin.org" target="_blank">http://www.paperin.org</a>)
055     * @version {@value com.softnetConsult.utils.APIProperties#apiVersion}
056     * 
057     * @see java.util.Random
058     */
059    public class FastRandom extends Random {
060    
061    /**
062     * Used internally for debug purposes.
063     */
064    private static final boolean generateDebugPrintout = true;
065    
066    /**
067     * Default buffer size for random booleans.
068     */
069    public static final int defaultBooleanBufferSize = 10000000;
070    
071    /**
072     * Default buffer size for random doubles.
073     */
074    public static final int defaultDoubleBufferSize = 10000000;
075    
076    /**
077     * Default buffer size for random ints.
078     */
079    public static final int defaultIntBufferSize = 10000000;
080    
081    
082    /**
083     * The buffer for random booleans.
084     */
085    private boolean [] booleanBuffer;
086    
087    /**
088     * The buffer for random doubles.
089     */
090    private double [] doubleBuffer;
091    
092    /**
093     * The buffer for random ints.
094     */
095    private int [] intBuffer;
096    
097    
098    /**
099     * Cursor for the boolean random numbers buffer.
100     */
101    private int booleanCursor;
102    
103    /**
104     * Cursor for the double random numbers buffer.
105     */
106    private int doubleCursor;
107    
108    /**
109     * Cursor for the int random numbers buffer.
110     */
111    private int intCursor;
112    
113    /**
114     * Flag to show that this object has readily initialised.
115     */
116    private boolean ready = false;
117    
118    
119    /**
120     * Creates a new {@code FastRandom} with default buffer sizes.
121     *
122     */
123    public FastRandom() {
124            this(defaultBooleanBufferSize, defaultDoubleBufferSize, defaultIntBufferSize);
125    }
126    
127    /**
128     * Creates a new {@code FastRandom} with default buffer sizes and a specified random seed.
129     * 
130     * @param seed Inital random seed.
131     */
132    public FastRandom(long seed) {
133            this(seed, defaultBooleanBufferSize, defaultDoubleBufferSize, defaultIntBufferSize);
134    }
135    
136    
137    /**
138     * Creates a new {@code FastRandom} with buffers of the specified size.
139     * 
140     * @param bufferSize The size for the random numbers buffers.
141     */
142    public FastRandom(int bufferSize) {
143            this(bufferSize, bufferSize, bufferSize);
144    }
145    
146    
147    /**
148     * Creates a new {@code FastRandom} with buffers of the specified size a specified random seed.
149     * 
150     * @param seed Inital random seed.
151     * @param bufferSize The size for the random numbers buffers.
152     */
153    public FastRandom(long seed, int bufferSize) {
154            this(seed, bufferSize, bufferSize, bufferSize);
155    }
156    
157    
158    /**
159     * Creates a new {@code FastRandom} with buffers of the specified size.
160     * 
161     * @param booleanBufferSize The size for the random {@code boolean} numbers buffer.
162     * @param doubleBufferSize The size for the random {@code double} numbers buffer.
163     * @param intBufferSize The size for the random {@code int} numbers buffer.
164     */
165    public FastRandom(int booleanBufferSize, int doubleBufferSize, int intBufferSize) {
166            super();
167            createBuffers(booleanBufferSize, doubleBufferSize, intBufferSize);
168            ready = true;
169            resetBuffers();
170    }
171    
172    
173    /**
174     * Creates a new {@code FastRandom} with buffers of the specified size a specified random seed.
175     * 
176     * @param seed Inital random seed.
177     * @param booleanBufferSize The size for the random {@code boolean} numbers buffer.
178     * @param doubleBufferSize The size for the random {@code double} numbers buffer.
179     * @param intBufferSize The size for the random {@code int} numbers buffer.
180     */
181    public FastRandom(long seed, int booleanBufferSize,int doubleBufferSize, int intBufferSize) {
182            super(seed);
183            createBuffers(booleanBufferSize, doubleBufferSize, intBufferSize);
184            ready = true;
185            resetBuffers();
186    }
187    
188    
189    /**
190     * Allocates the random buffer arrays.
191     * 
192     * @param booleanBufferSize The size for the random {@code boolean} numbers buffer.
193     * @param doubleBufferSize The size for the random {@code double} numbers buffer.
194     * @param intBufferSize The size for the random {@code int} numbers buffer.
195     */
196    private void createBuffers(int booleanBufferSize,int doubleBufferSize, int intBufferSize) {
197            booleanBuffer = new boolean[booleanBufferSize];
198            doubleBuffer = new double[doubleBufferSize];
199            intBuffer = new int[intBufferSize];
200    }
201    
202    
203    /**
204     * Sets the seed of this random number generator and then re-computes all buffers.
205     * 
206     * @param seed Inital random seed.
207     * @see java.util.Random#setSeed(long)
208     */
209    @Override
210    public void setSeed(long seed) {
211            super.setSeed(seed);
212            resetBuffers();
213    }
214    
215    
216    /**
217     * Returns the next pseudorandom {@code boolean}.
218     * The buffered random booleans are used as source.
219     * Once the buffer has been used up, it is used again from the start.
220     * 
221     * @return A pseudorandom {@code boolean}.
222     * @see java.util.Random#nextBoolean()
223     */
224    @Override
225    public boolean nextBoolean() {
226            if (booleanBuffer.length == booleanCursor)
227                    booleanCursor = 0;
228            return booleanBuffer[booleanCursor++];
229    }
230    
231    
232    /**
233     * Returns the next pseudorandom {@code double}.
234     * The buffered random doubles are used as source.
235     * Once the buffer has been used up, it is used again from the start.
236     * 
237     * @return A pseudorandom {@code double}.
238     * @see java.util.Random#nextDouble()
239     */
240    @Override
241    public double nextDouble() {
242            if (doubleBuffer.length == doubleCursor)
243                    doubleCursor = 0;
244            return doubleBuffer[doubleCursor++];
245    }
246    
247    
248    /**
249     * Returns the next pseudorandom {@code int}.
250     * The buffered random ints are used as source.
251     * Once the buffer has been used up, it is used again from the start.
252     * 
253     * @return A pseudorandom {@code int}.
254     * @see java.util.Random#nextInt()
255     */
256    @Override
257    public int nextInt() {
258            if (intBuffer.length == intCursor)
259                    intCursor = 0;
260            return intBuffer[intCursor++];
261    }
262    
263    
264    /**
265     * Used internally to fill the pseudorandom numbers buffers with values.
266     */
267    private void resetBuffers() {
268            
269            // Intro:
270            
271            if (!ready)
272                    return;
273            
274            Runtime rt = null;
275            if (generateDebugPrintout) {
276                    System.out.println("FastRandom generates buffers...");
277                    rt = Runtime.getRuntime();
278            }
279            
280            // Booleans:
281            
282            if (generateDebugPrintout) {
283                    System.out.printf("Current heap size: %,d KB. ", rt.totalMemory() / 1024);
284                    System.out.println("Generating boolean random buffer...");
285            }
286            
287            booleanCursor = 0;
288            for (int i = 0; i < booleanBuffer.length; i++)
289                    booleanBuffer[i] = super.nextBoolean();
290            
291            // Doubles:
292            
293            if (generateDebugPrintout) {
294                    System.out.printf("Current heap size: %,d KB. ", rt.totalMemory() / 1024);
295                    System.out.println("Generating double random buffer...");
296            }
297            
298            doubleCursor = 0;       
299            for (int i = 0; i < doubleBuffer.length; i++)
300                    doubleBuffer[i] = super.nextDouble();
301            
302            // Ints:
303            
304            if (generateDebugPrintout) {
305                    System.out.printf("Current heap size: %,d KB. ", rt.totalMemory() / 1024);
306                    System.out.println("Generating int random buffer...");
307            }
308            
309            intCursor = 0;
310            for (int i = 0; i < intBuffer.length; i++)
311                    intBuffer[i] = super.nextInt();
312            
313            // Done:
314            
315            if (generateDebugPrintout) {
316                    System.out.println("FastRandom completed generating buffers.");
317                    System.out.printf("Current heap size: %,d KB. ", rt.totalMemory() / 1024);
318                    System.out.println();
319            }       
320    }
321    
322    } // public class FastRandom