Reputation: 454
I am working with an ISAAC implementation which generates random integers. I need to create a Gaussian value with these integers. First, I need to change them to a double from 0 to 1 though. How can I do this in Java? Here is what I have so far to convert the ints to doubles, but it still needs to be in the normal distribution. I am also using java.util.Random.nextGaussian() logic to convert the double to Gaussian.
public double nextDouble() {
long l = ((long)(nextInt()) << 32) + nextInt();
return Double.longBitsToDouble(l);
}
What is the fastest possible way (cpu cycle wise) to do this?
Upvotes: 0
Views: 547
Reputation: 20080
Converting 64bit long to U(0,1) is not a simple task. I would recommend to read here.
As far as I can see, in Java world scalb
is equivalent to ldexp
, so code would be
public double nextDouble() {
return Math.scalb((double)nextLong(), -64);
}
Upvotes: 2
Reputation: 3212
If you want to use ISAAC by all means, then use the 64bit version that gives you a nextLong()
as a primitive. Generating a double is then simply
protected static final double DOUBLE_NORM = 1.0 / (1L << 53);
public double nextDouble() {
return (nextLong() >>> 11) * DOUBLE_NORM;
}
From there you can go on using Marsaglia's polar method for the nextGaussian()
method, the same way it is done in java.util.Random
Edit: I've tested 32bit & 64bit ISAAC a couple of years ago. Of course, I don't remember the exact numbers, but you might be surprised how much more throughput you can get with the 64bit version if you really need 64 random bits.
Edit 2: If you also need 32 random bits for integers you are of course wasting a lot of work with the 64bit algorithm (32bit is definitely faster here). In my work I need mostly doubles, so 64bit is the way to go (for me).
Edit 3: nextFloat()
would be
protected static final float FLOAT_NORM = 1.0F / (1 << 24);
public float nextFloat() {
return (nextLong() >>> 40) * FLOAT_NORM;
}
Upvotes: 3