/*
* 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);
}
}