OK, so the essential problem is that you need to do floating-point division, not integer division, as others have pointed out.
But I think fixing this particular code is sort of besides the point. Why bother with it in the first place? It's using essentially the same class of algorithm is java.lang.Random!
If you want a fast generator, consider an XORShift generator. If you want a good-quality generator, you have SecureRandom out of the box (though it's much slower), consider the Numerical Recipes algorithm (a fairly fast, combined generator), which you could implement in Java as follows:
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();
}
@Override
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;
return (x + v) ^ w;
} finally {
l.unlock();
}
}
protected int next(int bits) {
return (int) (nextLong() >>> (64-bits));
}
}
This is copied from some code where I needed it to be concurrent; you could get rid of the lock in principle, or just use regular synchronization.
If you absolutely insist on using Park-Miller-Carta, I'd at least wrap it in a Random subclass, and let java.util.Random take care of converting ints to doubles etc-- after all, that's what extensible libraries in an object-oriented language are for...