0

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?

Colby
  • 452
  • 4
  • 19
  • 1
    Your question is not clear. Try giving a few examples. Also, the normal distribution mu=0 sigma=1 may produce values outside (-1, 1) range. – vz0 Aug 31 '16 at 22:28
  • I'd use the 64bit ISAAC, then you could simply do `(nextLong() >>> 11) * (1.0 / (1L << 53))` – Stefan Zobel Aug 31 '16 at 22:31
  • Another question is why you want to use ISAAC at all. Speed? What quality do your random numbers need to have? I wouldn't recommend ISAAC for high-dimensional scientific simulations (let alone for cryptography). – Stefan Zobel Aug 31 '16 at 22:37
  • @StefanZobel That can be combined with "long l" in my original post to create the desired double values. Please rephrase as an answer and I will award. Thanks! – Colby Aug 31 '16 at 22:37
  • 1
    Sure. But do you have a 64bit ISAAC? Calling a 32bit ISAAC two times just to generate a long is quite inefficient. – Stefan Zobel Aug 31 '16 at 22:39
  • @StefanZobel My implementation is can generate around 65M integers per second on my system, while Java SecureRandom will generate about 10M integers per second. I am not using this for cryptography, however it needs to be unpredictable. Cycles are guaranteed to be at least 240 values long, and they are 28295 values long on average. – Colby Aug 31 '16 at 23:02
  • @StefanZobel How would I convert to 64bit? Would it really be worth it if I also am using integers as well? http://pastebin.com/ek4j0gaX – Colby Aug 31 '16 at 23:05
  • @StefanZobel Also that should be 2^240 and 2^28295 cycles, sorry – Colby Aug 31 '16 at 23:08

2 Answers2

3

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;
}
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
2

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);
}
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64
  • Thanks for the link, that's quite interesting. However, to be honest, I've never seen a Java PRNG implementation that cares about this :) It would also be interesting to know how big the performance difference is. Do you know anything about that? – Stefan Zobel Sep 01 '16 at 21:09
  • 2
    @StefanZobel On light RNG `ldexp/scalb` makes it a lot slower. On good heavy RNG like Mersenne Twister it adds up several percent to RNG call. But overall app slowdown is in the noise. I'm talking about experience in Monte Carlo in Fortran/C/C++. Have no idea how good or bad Java is... – Severin Pappadeux Sep 02 '16 at 16:35
  • Yes, that makes sense. Thanks for the information. I'm planning to run a little [JMH](http://openjdk.java.net/projects/code-tools/jmh/) micro benchmark for Java. AFAIK, `scalb` is currently not a JVM HotSpot [intrinsic](https://en.wikipedia.org/wiki/Intrinsic_function), so I'm curious about it. So, using `ldexp/scalb` instead of the simple-minded approach really makes a difference for something like MC(MC)? – Stefan Zobel Sep 02 '16 at 16:49