random.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.5.0).
003  * Copyright (c) 2007-2016 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.internal.math;
021 
022 import static java.lang.Math.abs;
023 import static java.lang.Math.nextDown;
024 import static java.lang.String.format;
025 import static org.jenetics.internal.util.require.probability;
026 
027 import java.util.Random;
028 import java.util.stream.IntStream;
029 
030 import org.jenetics.internal.util.require;
031 
032 /**
033  * Some random helper functions.
034  *
035  * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
036  * @since 1.4
037  * @version 3.0
038  */
039 public final class random {
040     private random() {require.noInstance();}
041 
042     public static byte nextByte(final Random random) {
043         return (byte)nextInt(random, Byte.MIN_VALUE, Byte.MAX_VALUE);
044     }
045 
046     public static char nextCharacter(final Random random) {
047         char c = '\0';
048         do {
049             c = (char)nextInt(random, Character.MIN_VALUE, Character.MAX_VALUE);
050         } while (!Character.isLetterOrDigit(c));
051 
052         return c;
053     }
054 
055     public static short nextShort(final Random random) {
056         return (short)nextInt(random, Short.MIN_VALUE, Short.MAX_VALUE);
057     }
058 
059     /**
060      * Returns a pseudo-random, uniformly distributed int value between min and
061      * max (min and max included).
062      *
063      * @param random the random engine to use for calculating the random int
064      *        value
065      * @param min lower bound for generated integer
066      * @param max upper bound for generated integer
067      * @return a random integer greater than or equal to {@code min} and
068      *         less than or equal to {@code max}
069      * @throws IllegalArgumentException if {@code min > max}
070      * @throws NullPointerException if the given {@code random}
071      *         engine is {@code null}.
072      */
073     public static int nextInt(
074         final Random random,
075         final int min, final int max
076     ) {
077         if (min > max) {
078             throw new IllegalArgumentException(format(
079                 "Min >= max: %d >= %d", min, max
080             ));
081         }
082 
083         final int diff = max - min + 1;
084         int result = 0;
085 
086         if (diff <= 0) {
087             do {
088                 result = random.nextInt();
089             } while (result < min || result > max);
090         } else {
091             result = random.nextInt(diff) + min;
092         }
093 
094         return result;
095     }
096 
097     /**
098      * Returns a pseudo-random, uniformly distributed int value between min
099      * and max (min and max included).
100      *
101      * @param random the random engine to use for calculating the random
102      *        long value
103      * @param min lower bound for generated long integer
104      * @param max upper bound for generated long integer
105      * @return a random long integer greater than or equal to {@code min}
106      *         and less than or equal to {@code max}
107      * @throws IllegalArgumentException if {@code min > max}
108      * @throws NullPointerException if the given {@code random}
109      *         engine is {@code null}.
110      */
111     public static long nextLong(
112         final Random random,
113         final long min, final long max
114     ) {
115         if (min > max) {
116             throw new IllegalArgumentException(format(
117                 "min >= max: %d >= %d.", min, max
118             ));
119         }
120 
121         final long diff = (max - min) + 1;
122         long result = 0;
123 
124         if (diff <= 0) {
125             do {
126                 result = random.nextLong();
127             } while (result < min || result > max);
128         } else if (diff < Integer.MAX_VALUE) {
129             result = random.nextInt((int)diff) + min;
130         } else {
131             result = nextLong(random, diff) + min;
132         }
133 
134         return result;
135     }
136 
137     /**
138      * Returns a pseudo-random, uniformly distributed int value between 0
139      * (inclusive) and the specified value (exclusive), drawn from the given
140      * random number generator's sequence.
141      *
142      * @param random the random engine used for creating the random number.
143      * @param n the bound on the random number to be returned. Must be
144      *        positive.
145      * @return the next pseudo-random, uniformly distributed int value
146      *         between 0 (inclusive) and n (exclusive) from the given random
147      *         number generator's sequence
148      * @throws IllegalArgumentException if n is smaller than 1.
149      * @throws NullPointerException if the given {@code random}
150      *         engine is {@code null}.
151      */
152     public static long nextLong(final Random random, final long n) {
153         if (n <= 0) {
154             throw new IllegalArgumentException(format(
155                 "n is smaller than one: %d", n
156             ));
157         }
158 
159         long bits;
160         long result;
161         do {
162             bits = random.nextLong() & 0x7fffffffffffffffL;
163             result = bits%n;
164         } while (bits - result + (n - 1) < 0);
165 
166         return result;
167     }
168 
169     /**
170      * Returns a pseudo-random, uniformly distributed double value between
171      * min (inclusively) and max (exclusively).
172      *
173      * @param random the random engine used for creating the random number.
174      * @param min lower bound for generated float value (inclusively)
175      * @param max upper bound for generated float value (exclusively)
176      * @return a random float greater than or equal to {@code min} and less
177      *         than to {@code max}
178      * @throws NullPointerException if the given {@code random}
179      *         engine is {@code null}.
180      */
181     public static float nextFloat(
182         final Random random,
183         final float min, final float max
184     ) {
185         if (min >= max) {
186             throw new IllegalArgumentException(format(
187                 "min >= max: %f >= %f.", min, max
188             ));
189         }
190 
191         float value = random.nextFloat();
192         if (min < max) {
193             value = value*(max - min) + min;
194             if (value >= max) {
195                 value = nextDown(value);
196             }
197         }
198 
199         return value;
200     }
201 
202     /**
203      * Returns a pseudo-random, uniformly distributed double value between
204      * min (inclusively) and max (exclusively).
205      *
206      * @param random the random engine used for creating the random number.
207      * @param min lower bound for generated double value (inclusively)
208      * @param max upper bound for generated double value (exclusively)
209      * @return a random double greater than or equal to {@code min} and less
210      *         than to {@code max}
211      * @throws NullPointerException if the given {@code random}
212      *         engine is {@code null}.
213      */
214     public static double nextDouble(
215         final Random random,
216         final double min, final double max
217     ) {
218         if (min >= max) {
219             throw new IllegalArgumentException(format(
220                 "min >= max: %f >= %f.", min, max
221             ));
222         }
223 
224         double value = random.nextDouble();
225         if (min < max) {
226             value = value*(max - min) + min;
227             if (value >= max) {
228                 value = nextDown(value);
229             }
230         }
231 
232         return value;
233     }
234 
235     public static String nextString(final Random random, final int length) {
236         final char[] chars = new char[length];
237         for (int i = 0; i < length; ++i) {
238             chars[i] = nextCharacter(random);
239         }
240 
241         return new String(chars);
242     }
243 
244     public static String nextString(final Random random) {
245         return nextString(random, nextInt(random, 5, 20));
246     }
247 
248     /*
249      * Conversion methods used by the 'Random' engine from the JDK.
250      */
251 
252     public static float toFloat(final int a) {
253         return (a >>> 8)/((float)(1 << 24));
254     }
255 
256     public static float toFloat(final long a) {
257         return (int)(a >>> 40)/((float)(1 << 24));
258     }
259 
260     public static double toDouble(final long a) {
261         return (((a >>> 38) << 27) + (((int)a) >>> 5))/(double)(1L << 53);
262     }
263 
264     public static double toDouble(final int a, final int b) {
265         return (((long)(a >>> 6) << 27) + (b >>> 5))/(double)(1L << 53);
266     }
267 
268     /*
269      * Conversion methods used by the Apache Commons BitStreamGenerator.
270      */
271 
272     public static float toFloat2(final int a) {
273         return (a >>> 9)*0x1.0p-23f;
274     }
275 
276     public static float toFloat2(final long a) {
277         return (int)(a >>> 41)*0x1.0p-23f;
278     }
279 
280     public static double toDouble2(final long a) {
281         return (a & 0xFFFFFFFFFFFFFL)*0x1.0p-52d;
282     }
283 
284     public static double toDouble2(final int a, final int b) {
285         return (((long)(a >>> 6) << 26) | (b >>> 6))*0x1.0p-52d;
286     }
287 
288     /**
289      * Create an {@code IntStream} which creates random indexes within the
290      * given range and the index probability.
291      *
292      * @since 3.0
293      *
294      * @param random the random engine used for calculating the random
295      *        indexes
296      * @param start the start index (inclusively)
297      * @param end the end index (exclusively)
298      * @param p the index selection probability
299      * @return an new random index stream
300      * @throws IllegalArgumentException if {@code p} is not a
301      *         valid probability.
302      */
303     public static IntStream indexes(
304         final Random random,
305         final int start,
306         final int end,
307         final double p
308     ) {
309         probability(p);
310         final int P = probability.toInt(p);
311 
312         return equals(p, 0, 1E-20)
313             ? IntStream.empty()
314             : equals(p, 1, 1E-20)
315                 ? IntStream.range(start, end)
316                 : IntStream.range(start, end)
317                     .filter(i -> random.nextInt() < P);
318     }
319 
320     private static
321     boolean equals(final double a, final double b, final double delta) {
322         return abs(a - b) <= delta;
323     }
324 
325     /**
326      * Create an {@code IntStream} which creates random indexes within the
327      * given range and the index probability.
328      *
329      * @since 3.0
330      *
331      * @param random the random engine used for calculating the random
332      *        indexes
333      * @param n the end index (exclusively). The start index is zero.
334      * @param p the index selection probability
335      * @return an new random index stream
336      * @throws IllegalArgumentException if {@code p} is not a
337      *         valid probability.
338      * @throws NullPointerException if the given {@code random}
339      *         engine is {@code null}.
340      */
341     public static IntStream indexes(
342         final Random random,
343         final int n,
344         final double p
345     ) {
346         return indexes(random, 0, n, p);
347     }
348 
349     /**
350      * Create a new <em>seed</em> byte array of the given length.
351      *
352      * @see #seed(byte[])
353      * @see #seed()
354      *
355      * @param length the length of the returned byte array.
356      * @return a new <em>seed</em> byte array of the given length
357      * @throws NegativeArraySizeException if the given length is smaller
358      *         than zero.
359      */
360     public static byte[] seedBytes(final int length) {
361         return seed(new byte[length]);
362     }
363 
364     /**
365      * Fills the given byte array with random bytes, created by successive
366      * calls of the {@link #seed()} method.
367      *
368      * @see #seed()
369      *
370      * @param seed the byte array seed to fill with random bytes.
371      * @return the given byte array, for method chaining.
372      * @throws NullPointerException if the {@code seed} array is
373      *         {@code null}.
374      */
375     public static byte[] seed(final byte[] seed) {
376         for (int i = 0, len = seed.length; i < len;) {
377             int n = Math.min(len - i, Long.SIZE/Byte.SIZE);
378 
379             for (long x = seed(); n-- > 0; x >>= Byte.SIZE) {
380                 seed[i++] = (byte)x;
381             }
382         }
383 
384         return seed;
385     }
386 
387     /**
388      * Calculating a 64 bit seed value which can be used for initializing
389      * PRNGs. This method uses a combination of {@code System.nanoTime()}
390      * and {@code new Object().hashCode()} calls to create a reasonable safe
391      * seed value:
392      * <p>
393      * <pre>{@code
394      * public static long seed() {
395      *     return seed(System.nanoTime());
396      * }
397      * }</pre>
398      * <p>
399      * This method passes all of the statistical tests of the
400      * <a href="http://www.phy.duke.edu/~rgb/General/dieharder.php">
401      * dieharder</a> test suite&mdash;executed on a linux machine with
402      * JDK version 1.7. <em>Since there is no prove that this will the case
403      * for every Java version and OS, it is recommended to only use this
404      * method for seeding other PRNGs.</em>
405      *
406      * @see #seed(long)
407      *
408      * @return the random seed value.
409      */
410     public static long seed() {
411         return seed(System.nanoTime());
412     }
413 
414     /**
415      * Uses the given {@code base} value to create a reasonable safe seed
416      * value. This is done by combining it with values of
417      * {@code new Object().hashCode()}:
418      * <p>
419      * <pre>{@code
420      * public static long seed(final long base) {
421      *     final long objectHashSeed = ((long)(new Object().hashCode()) << 32) |
422      *                                         new Object().hashCode();
423      *     long seed = base^objectHashSeed;
424      *     seed ^= seed << 17;
425      *     seed ^= seed >>> 31;
426      *     seed ^= seed << 8;
427      *     return seed;
428      * }
429      * }</pre>
430      *
431      * @param base the base value of the seed to create
432      * @return the created seed value.
433      */
434     public static long seed(final long base) {
435         return mix(base, objectHashSeed());
436     }
437 
438     private static long mix(final long a, final long b) {
439         long c = a^b;
440         c ^= c << 17;
441         c ^= c >>> 31;
442         c ^= c << 8;
443         return c;
444     }
445 
446     private static long objectHashSeed() {
447         return (long)new Object().hashCode() << 32 | new Object().hashCode();
448     }
449 }