Stream-Based Linear Congruential Generator in Java 8
A while ago, I wrote a post on a Stream-Based Linear Congruential Generator in Scala. This post is a similar implementation using the Java 8 Stream API.
Here is a Java 8 stream-based implementation of a pseudo-random number generator using a linear congruential generator (LCG):
package com.michaelcotterell.util; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; public class Random { private final long a; // multiplier private final long c; // increment private final long m; // modulus private final long seed; // start value private final LongStream stream; public Random(long a, long c, long m, long seed) { this.a = a; this.c = c; this.m = m; this.seed = seed % m; this.stream = LongStream.iterate(this.seed, x -> (a * x + c) % m); } // Random public Random(long a, long c, long m) { this(a, c, m, System.currentTimeMillis()); } // Random public LongStream longs() { return stream.map(e -> e); } // longs public IntStream ints() { return stream.mapToInt(e -> (int) (e % (Integer.MAX_VALUE + 1L))); } // ints public DoubleStream doubles() { final double ONE_OVER_M = 1.0 / m; return stream.mapToDouble(e -> e * ONE_OVER_M); } // doubles } // Random
To use this class, you might do something like the following:
Random lcg = new Random(48271, 0, (2L << 31) - 1, System.currentTimeMillis()); Iterator<Double> rand = lcg.doubles().iterator(); for (int i = 0; i < 10; ++i) System.out.println(rand.next());
To test different LCGs, you might do the following:
long iters = 100_000; long seed = System.currentTimeMillis(); Random[] lcgs = new Random[] { new Random(48271, 0, (2L << 31) - 1, seed), // MINSTD (updated) new Random(16807, 0, (2L << 31) - 1, seed), // MINSTD (old) new Random(65539, 0, (2L << 31), seed) // RANDU }; for (Random lcg : lcgs) { System.out.println(lcg.doubles().limit(iters).summaryStatistics()); } // for