/* * Copyright 2014 Jeff Hain * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jafaran; import java.util.Random; /** * Abstract class for all RNGs, which extends Random, * and overrides its spec by removing the thread-safety necessity * (we give ourselves the right to do so). * * Provides additional methods, or faster implementations of Random ones, * especially for nextDouble() and nextGaussian(). * * Unlike for Random, the core source of randomness is not next(int), * but nextInt() and/or nextLong(). * By default, these methods delegate to each other, together to force each * implementation to override at least one of them (else causes call stack * overflow) and not to force it to override them both. * By default as well, next(int) delegates to nextInt(), but it can still be * overriden. * * nextBoolean(), nextBit(), nextByte() and nextShort() all use next(int), * in case it would store and reuse unused random bits, which can make things * faster since these methods don't use most of the bits generated by * nextInt() or nextLong(), and also allows not to waste generated * pseudo-randomness (better period). * Other methods, i.e. methods using more than 16 random bits, use nextInt() * and/or nextLong(). * * Random.setSeed(long) is called in Random's constructors, i.e. before * constructors of instances extending Random have been called, and is * overridable, which can cause trouble. * construct() and setSeedImpl(long) methods are provided to make * construction and seed setting simpler with respect to that problem. * Also, it allows constructors of classes extending AbstractRNG to just call * super class constructor of same signature. */ public abstract class AbstractRNG extends Random { //-------------------------------------------------------------------------- // MEMBERS //-------------------------------------------------------------------------- private static final long serialVersionUID = 1L; /** * Could as well be non-final, but adding final shouldn't hurt, and could * even help if extending classes publish "this" in their constructors. */ private final boolean constructCalled; //-------------------------------------------------------------------------- // PUBLIC METHODS //-------------------------------------------------------------------------- /** * Constructor using a random seed. */ public AbstractRNG() { this(RandomUtilz.longPseudoEntropy()); } /** * Constructor using a specified seed. */ public AbstractRNG(long seed) { this(null); this.setSeed(seed); } @Override public final void setSeed(long seed) { if (!this.constructCalled) { // Call from Random's constructor: ignoring it // (will be called afterwards from our constructors). return; } this.setSeedImpl(seed); } /* * uniform */ /** * Can be more handy and faster than nextBoolean(), depending on usage. * * @return Uniform int in [0,1]. */ public int nextBit() { // Not returning a byte, for the cast takes time, // and since byte type is auto-casted in int before // most operations, we usually don't need it. // This is not homogeneous with nextByte() and nextShort(), // for which we cast, but this method is already unlike these // in that it interprets computed bit as unsigned (in [0,2^size-1]) // instead of signed (in [-2^(size-1),2^(size-1)-1]). return this.next(1); } /** * @return Uniform byte. */ public byte nextByte() { return (byte)this.next(8); } /** * @return Uniform short. */ public short nextShort() { return (short)this.next(16); } /** * @return Uniform int. */ @Override public int nextInt() { return (int)this.nextLong(); } /** * @return Uniform long. */ @Override public long nextLong() { return ((long)this.nextInt() << 32) + this.nextInt(); } /** * @return Uniform float in [0,1-1/2^24], with 1/2^24 granularity. */ @Override public float nextFloat() { return (this.nextInt() & ((1<<24)-1)) * (1.0f/(1<<24)); } /** * @return Uniform double in [0,1-1/2^53], with 1/2^53 granularity. */ @Override public double nextDouble() { return (this.nextLong() & ((1L<<53)-1)) * (1.0/(1L<<53)); } /** * @return Uniform double in [0,1-1/2^31], with 1/2^31 granularity. */ public double nextDoubleFast() { if (false) { // Might be faster in C, but seems slower here. long x = (((long)(this.nextInt() & Integer.MAX_VALUE)) << (52-31)) | 0x3FF0000000000000L; double a = Double.longBitsToDouble(x); return a - 1.0; } return (this.nextInt() & Integer.MAX_VALUE) * (1.0/(1L<<31)); } /** * @return Uniform int in [0,n[. */ @Override public int nextInt(int n) { if (n <= 0) { throw new IllegalArgumentException("n must be positive"); } if ((n & -n) == n) { return (int)((n * (long)(nextInt() & Integer.MAX_VALUE)) >> 31); } int bits; int val; do { bits = (this.nextInt() & Integer.MAX_VALUE); val = bits % n; } while (bits - val + (n-1) < 0); return val; } /** * @return Uniform long in [0,n[. */ public long nextLong(long n) { if (n <= Integer.MAX_VALUE) { // Faster. // Check here because cast might turn a huge negative value // into a positive value. if (n <= 0) { throw new IllegalArgumentException("n must be positive"); } return this.nextInt((int)n); } long bits; long val; do { bits = (this.nextLong() & Long.MAX_VALUE); val = bits % n; } while (bits - val + (n-1) < 0); return val; } /* * gaussian */ /** * @return Normal gaussian double. */ @Override public double nextGaussian() { return Ziggurat.nextGaussian(this); } /** * @return Normal gaussian double, possibly with more non-random LSBits * in the mantissa than nextGaussian(), but typically faster. */ public double nextGaussianFast() { return Ziggurat.nextGaussianFast(this); } /* * state get/set */ /** * Default implementation throws UnsupportedOperationException. * * @return An array containing the state of this RNG. * @throws UnsupportedOperationException if state retrieval is not * available, for example due to this RNG not being a Pseudo-RNG. */ public byte[] getState() { throw new UnsupportedOperationException(); } /** * Default implementation throws UnsupportedOperationException. * * @param state State of a compatible RNG (typically of the same class), * as returned by getState() method (length matters). * @throws UnsupportedOperationException if state setting is not available, * for example due to this RNG not being a Pseudo-RNG. * @throws NullPointerException if the specified state is null. */ public void setState(byte[] state) { throw new UnsupportedOperationException(); } //-------------------------------------------------------------------------- // PROTECTED METHODS //-------------------------------------------------------------------------- /** * Constructor that does not call setSeed(long), which allows for creation * without setSeed(long) overhead, and then to use another initialization. * * Using Void as dummy argument type, for it's unlikely that a RNG * constructor with a used single argument would use it. * * Typical usage: constructor((Void)null) * (cast to avoid ambiguity). * * @param dummy Argument only useful to type the constructor. */ protected AbstractRNG(Void dummy) { // Calling Random(long) to avoid generation of a seed. super(0L); this.construct(); this.constructCalled = true; } /** * Overriden implementations may or may not have to call super * implementation. */ protected void construct() { } /** * Override this method to implement your generator's * reset with the specified seed. */ protected void setSeedImpl(long seed) { // Not calling super.setSeed(long): // it is useless, and is synchronized. } /** * This implementation delegates to nextInt(). * Can be overriden, typically for performances, like avoiding * a method call, or storing and reusing unused random bits. */ @Override protected int next(int bits) { return this.nextInt()>>>(32-bits); } }