class SplittableRandom

Jeff Hain jeffhain at rocketmail.com
Thu Jul 11 19:50:12 UTC 2013


Hello.



1) extending Random

Doug Lea wrote:
>Q: Why isn't SplittableRandom a subclass of Random?
>A: Class Random requires thread-safety in its spec. It would be
>nonsensical for SplittableRandom to comply.

Random Javadoc states "Instances of java.util.Random are threadsafe."
but ThreadLocalRandom extends Random and is not, so why not consider
that the thread-safety statement only applies to Random.class, and
not to Random subclasses?



2) third alternative

Doug Lea wrote:
>If you want to create a stream of random numbers to drive a parallel
>computation, you'd choose among two options, neither of them providing
>what you probably want: (1) Use a stream based on a single shared
>java.util.Random object, in which case your program will encounter
>stunning slowdowns when run with many cores; or (2) Use a stream based
>on ThreadLocalRandom,

What I would have used (maybe because I'm not an expert!) is something
like this:
    new Subtask(new MySequentialRandom(currentTaskRandom.nextLong())).fork()
with nextLong() returning something else than current seed of course,
to avoid ending up with the same sequence of pseudo-random numbers.

In what way would
    new Subtask(aSplittableRandom.split()).fork()
be better than that?

The Javadoc for split() says that the values of the returned object
should have the same (i.e. as good?) statistical properties, but wouldn't
it also be the case with a good non-thread-safe Random, like based on
MersenneTwister, which could be seeded with multiple longs?



3) nextDouble()

With this method:
    public double nextDouble() {
        long bits = (1023L << 52) | (nextLong() >>> 12);
        return Double.longBitsToDouble(bits) - 1.0;
    }
the returned value granularity is only 1/2^52,
i.e. last mantissa bit is always zero.
For example the highest value you can return is
1.9999999999999998 - 1.0
i.e.
0.9999999999999998
and so
0.9999999999999999 
is never returned.

One could use that instead, which doesn't have that problem,
and provides values in [0,1-1/2^53], with 1/2^53 granularity:
    public double nextDouble() {
        return (this.nextLong() & ((1L<<53)-1)) * (1.0/(1L<<53));
    }
but it can be a bit slower (maybe due to cast of huge longs
into double being slow on some architectures).
If needing speed over accuracy, one can replace nextLong() with
nextInt(), mask with Integer.MAX_VALUE, and 53 with 31.



4) nextGaussian()

Currently there is no nextGaussian():
if added, would it use Random/TLR's algorithm,
or some variation of the Ziggurat method
(which can be about four times faster)?



-Jeff


More information about the core-libs-dev mailing list