/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* 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 com.badlogic.gdx.math;
import java.util.Random;
/**
* This class implements the xorshift128+ algorithm that is a very fast,
* top-quality 64-bit pseudo-random number generator. The quality of this PRNG
* is much higher than {@link Random}'s, and its cycle length is 2<sup>128</sup>
* − 1, which is more than enough for any single-thread
* application. More details and algorithms can be found
* <a href="http://xorshift.di.unimi.it/">here</a>.
* <p>
* Instances of RandomXS128 are not thread-safe.
*
* @author Inferno
* @author davebaol
*/
public class RandomXS128 extends Random {
/** Normalization constant for double. */
private static final double NORM_DOUBLE = 1.0 / (1L << 53);
/** Normalization constant for float. */
private static final double NORM_FLOAT = 1.0 / (1L << 24);
/**
* The first half of the internal state of this pseudo-random number
* generator.
*/
private long seed0;
/**
* The second half of the internal state of this pseudo-random number
* generator.
*/
private long seed1;
/**
* Creates a new random number generator. This constructor sets the seed of
* the random number generator to a value very likely to be distinct from
* any other invocation of this constructor.
* <p>
* This implementation creates a {@link Random} instance to generate the
* initial seed.
*/
public RandomXS128() {
setSeed(new Random().nextLong());
}
/**
* Creates a new random number generator using a single {@code long} seed.
*
* @param seed
* the initial seed
*/
public RandomXS128(long seed) {
setSeed(seed);
}
/**
* Creates a new random number generator using two {@code long} seeds.
*
* @param seed0
* the first part of the initial seed
* @param seed1
* the second part of the initial seed
*/
public RandomXS128(long seed0, long seed1) {
setState(seed0, seed1);
}
/**
* Returns the next pseudo-random, uniformly distributed {@code long} value
* from this random number generator's sequence.
* <p>
* Subclasses should override this, as this is used by all other methods.
*/
@Override
public long nextLong() {
long s1 = this.seed0;
final long s0 = this.seed1;
this.seed0 = s0;
s1 ^= s1 << 23;
return (this.seed1 = (s1 ^ s0 ^ (s1 >>> 17) ^ (s0 >>> 26))) + s0;
}
/**
* This protected method is final because, contrary to the superclass, it's
* not used anymore by the other methods.
*/
@Override
protected final int next(int bits) {
return (int) (nextLong() & ((1L << bits) - 1));
}
/**
* Returns the next pseudo-random, uniformly distributed {@code int} value
* from this random number generator's sequence.
* <p>
* This implementation uses {@link #nextLong()} internally.
*/
@Override
public int nextInt() {
return (int) nextLong();
}
/**
* Returns a pseudo-random, uniformly distributed {@code int} value between
* 0 (inclusive) and the specified value (exclusive), drawn from this random
* number generator's sequence.
* <p>
* This implementation uses {@link #nextLong()} internally.
*
* @param n
* the positive bound on the random number to be returned.
* @return the next pseudo-random {@code int} value between {@code 0}
* (inclusive) and {@code n} (exclusive).
*/
@Override
public int nextInt(final int n) {
return (int) nextLong(n);
}
/**
* Returns a pseudo-random, uniformly distributed {@code long} value between
* 0 (inclusive) and the specified value (exclusive), drawn from this random
* number generator's sequence. The algorithm used to generate the value
* guarantees that the result is uniform, provided that the sequence of
* 64-bit values produced by this generator is.
* <p>
* This implementation uses {@link #nextLong()} internally.
*
* @param n
* the positive bound on the random number to be returned.
* @return the next pseudo-random {@code long} value between {@code 0}
* (inclusive) and {@code n} (exclusive).
*/
public long nextLong(final long n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
for (;;) {
final long bits = nextLong() >>> 1;
final long value = bits % n;
if (bits - value + (n - 1) >= 0)
return value;
}
}
/**
* Returns a pseudo-random, uniformly distributed {@code double} value
* between 0.0 and 1.0from this random number generator's sequence.
* <p>
* This implementation uses {@link #nextLong()} internally.
*/
@Override
public double nextDouble() {
return (nextLong() >>> 11) * NORM_DOUBLE;
}
/**
* Returns a pseudo-random, uniformly distributed {@code float} value
* between 0.0 and 1.0 from this random number generator's sequence.
* <p>
* This implementation uses {@link #nextLong()} internally.
*/
@Override
public float nextFloat() {
return (float) ((nextLong() >>> 40) * NORM_FLOAT);
}
/**
* Returns a pseudo-random, uniformly distributed {@code boolean } value
* from this random number generator's sequence.
* <p>
* This implementation uses {@link #nextLong()} internally.
*/
@Override
public boolean nextBoolean() {
return (nextLong() & 1) != 0;
}
/**
* Generates random bytes and places them into a user-supplied byte array.
* The number of random bytes produced is equal to the length of the byte
* array.
* <p>
* This implementation uses {@link #nextLong()} internally.
*/
@Override
public void nextBytes(final byte[] bytes) {
int n = 0;
int i = bytes.length;
while (i != 0) {
n = i < 8 ? i : 8; // min(i, 8);
for (long bits = nextLong(); n-- != 0; bits >>= 8)
bytes[--i] = (byte) bits;
}
}
/**
* Sets the internal seed of this generator based on the given {@code long}
* value.
* <p>
* The given seed is passed twice through an hash function. This way, if the
* user passes a small value we avoid the short irregular transient
* associated with states having a very small number of bits set.
*
* @param seed
* a nonzero seed for this generator (if zero, the generator will
* be seeded with {@link Long#MIN_VALUE}).
*/
@Override
public void setSeed(final long seed) {
long seed0 = murmurHash3(seed == 0 ? Long.MIN_VALUE : seed);
setState(seed0, murmurHash3(seed0));
}
/**
* Sets the internal state of this generator.
*
* @param seed0
* the first part of the internal state
* @param seed1
* the second part of the internal state
*/
public void setState(final long seed0, final long seed1) {
this.seed0 = seed0;
this.seed1 = seed1;
}
/**
* Returns the internal seeds to allow state saving.
*
* @param seed
* muse be 0 or 1, designating which of the 2 long seeds to
* return
* @return the internal seed that can be used in setState
*/
public long getState(int seed) {
return seed == 0 ? seed0 : seed1;
}
private final static long murmurHash3(long x) {
x ^= x >>> 33;
x *= 0xff51afd7ed558ccdL;
x ^= x >>> 33;
x *= 0xc4ceb9fe1a85ec53L;
x ^= x >>> 33;
return x;
}
}