A Java implementation of the Numerical Recipies random number generator
In many applications, the ThreadLocalRandom class provides a fast, medium-quality random
number generator that performs well on statistical tests. It has a period of 264, sufficient for many applications.
Here, we show how we can easily subclass java.util.Random with an implementation
of a higher-quality RNG. This example is the "highest quality recommended generator" outlined in Numerical Recipes (see 3rd Ed, p. 342).
It is a combined generator: it combines two 64-bit XORShift generators with a 64-bit LCG plus
a so-called multiply-with-carry (MWC) generator. It has 192 bits of state and hence a period in the order of 2191
(not strictly 2192, as the MWC component has a period of 263).
A general contract of the java.lang.Random is that it should be thread-safe. We make our subclass thread-safe by
using a ReentrantLock and, for simplicity, we lock the entire instance for the duration of the generation routine.
public class HighQualityRandom extends Random {
private Lock l = new ReentrantLock();
private long u;
private long v = 4101842887655102017L;
private long w = 1;
public HighQualityRandom() {
this(System.nanoTime());
}
public HighQualityRandom(long seed) {
l.lock();
u = seed ^ v;
nextLong();
v = u;
nextLong();
w = v;
nextLong();
l.unlock();
}
public long nextLong() {
l.lock();
try {
u = u * 2862933555777941757L + 7046029254386353087L;
v ^= v >>> 17;
v ^= v << 31;
v ^= v >>> 8;
w = 4294957665L * (w & 0xffffffff) + (w >>> 32);
long x = u ^ (u << 21);
x ^= x >>> 35;
x ^= x << 4;
long ret = (x + v) ^ w;
return ret;
} finally {
l.unlock();
}
}
protected int next(int bits) {
return (int) (nextLong() >>> (64-bits));
}
}
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.