package io.vivarium.util; import java.util.Random; public class Rand { // Allocator instance, this needs to be changed to get good performance in a multi-threaded // environment, but needs to use the SimpleRandAllocator to work with GWT by default. private static RandAllocator _allocator = new SimpleRandAllocator(); // Random number state private Random _random = new Random(); private long _randomLong = (long) (_random.nextDouble() * (Long.MAX_VALUE - 1) + 1); private long _randomLong2 = (long) (_random.nextDouble() * (Long.MAX_VALUE - 1) + 1); public static Rand getInstance() { return _allocator.getInstance(); } public synchronized static void setAllocator(RandAllocator allocator) { _allocator = allocator; } /** * Sets the psuedorandom seed to generate predictable behavior. javaRandomDouble uses LCG and this class has a * slightly faster Xorshift algorithm. Setting this seed will set the seeds for both the LCG and Xorshift seeds, * which become independent after the initial set. * * If this seed is not set, the LCG randoms will be initialized by the default java.util.Random() constructor, and * the Xorshift seed will be generated by the first value taken from the Random instance. * * @param seed * the seed to set, must not be zero */ public void setRandomSeed(int seed) { if (seed == 0) { throw new Error("Random seeds cannot be zero"); } _random = new Random(seed); _randomLong = seed; _randomLong2 = seed; } /** * Sets the seed to a psuedorandomly generated value. This is useful for test clearing a deliberately set seed in * test cases. */ public void setRandomSeed() { // _random = new Random(); _randomLong = (long) (_random.nextDouble() * (Long.MAX_VALUE - 1) + 1); } /** * Get a psuedorandom double with the range (-1,1) * * @return A psuedorandom double */ public double getRandomDouble() { return (double) getRandomLong() / Long.MAX_VALUE; } /** * Get a psuedorandom positive double with the range [0,1) * * @return A psuedorandom double */ public double getRandomPositiveDouble() { return _random.nextDouble(); } /** * Get a psuedorandom int with range [0,range) * * @param range * the number of possible return values * @return A psuedorandom double [0,range) */ public int getRandomInt(int range) { return _random.nextInt(range); } /** * Get a psuedorandom double from a Gaussian distribution with a mean of 0.0 and a standard deviation of 1.0 * * @return A psuedorandom Gaussian double */ public double getRandomGaussian() { return _random.nextGaussian(); } /** * Get a psuedorandom long generated with XorShift. * * @return A psuedorandom long */ public long getRandomLong() { _randomLong ^= (_randomLong << 21); _randomLong ^= (_randomLong >>> 35); _randomLong ^= (_randomLong << 4); return _randomLong; } /** * Get a psuedorandom long generated with XorShift. This long uses a different seed from the getRandomLong method, * in case a caller needs two independent random numbers. * * @return A psuedorandom long */ public long getRandomLong2() { _randomLong2 ^= (_randomLong2 << 21); _randomLong2 ^= (_randomLong2 >>> 35); _randomLong2 ^= (_randomLong2 << 4); return _randomLong2; } }