newrandom/Rng.java
author briangoetz
Thu, 23 May 2019 16:45:56 -0400
branchbriangoetz-test-branch
changeset 57369 6d87e9f7a1ec
permissions -rwxr-xr-x
Initial comment in newrandom/

/*
 * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
// package java.util;

import java.math.BigInteger;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

/**
 * The {@code Rng} interface is designed to provide a common protocol
 * for objects that generate random or (more typically) pseudorandom
 * sequences of numbers (or Boolean values).  Such a sequence may be
 * obtained by either repeatedly invoking a method that returns a
 * single (pseudo)randomly chosen value, or by invoking a method that
 * returns a stream of (pseudo)randomly chosen values.
 *
 * <p>Ideally, given an implicitly or explicitly specified range of values,
 * each value would be chosen independently and uniformly from that range.
 * In practice, one may have to settle for some approximation to independence
 * and uniformity.
 *
 * <p>In the case of {@code int}, {@code long}, and {@code Boolean}
 * values, if there is no explicit specification of range, then the
 * range includes all possible values of the type.  In the case of
 * {@code float} and {@code double} values, a value is always chosen
 * from the set of 2<sup><it>w</it></sup> values between 0.0 (inclusive)
 * and 1.0 (exclusive), where <it>w</it> is 23 for {@code float}
 * values and 52 for {@code double} values, such that adjacent values
 * differ by 2<sup>&minus;<it>w</it></sup>; if an explicit range is
 * specified, then the chosen number is computationally scaled and
 * translated so as to appear to have been chosen from that range.
 *
 * <p>Each method that returns a stream produces a stream of values each of
 * which is chosen in the same manner as for a method that
 * returns a single (pseudo)randomly chosen value.  For example, if {@code r}
 * implements {@code Rng}, then the method call {@code r.ints(100)} returns
 * a stream of 100 {@code int} values.  These are not necessarily the exact
 * same values that would have been returned if instead {@code r.nextInt()}
 * had been called 100 times; all that is guaranteed is that each value in
 * the stream is chosen in a similar (pseudo)random manner from the same range.
 *
 * <p>Every object that implements the {@code Rng} interface is assumed
 * to contain a finite amount of state.  Using such an object to
 * generate a pseudorandomly chosen value alters its state.  The
 * number of distinct possible states of such an object is called its
 * <it>period</it>.  (Some implementations of the {@code Rng} interface
 * may be truly random rather than pseudorandom, for example relying
 * on the statistical behavior of a physical object to derive chosen
 * values.  Such implementations do not have a fixed period.)
 *
 * <p>As a rule, objects that implement the {@code Rng} interface need not
 * be thread-safe.  It is recommended that multithreaded applications
 * use either {@code ThreadLocalRandom} or (preferably) pseudorandom
 * number generators that implement the {@code SplittableRng} or
 * {@code JumpableRng} interface.

 * To implement this interface, a class only needs to provide concrete
 * definitions for the methods {@code nextLong()} and {@code period()}.
 * Default implementations are provided for all other methods
 * (but it may be desirable to override some of them, especially
 * {@code nextInt()} if the underlying algorithm is {@code int}-based).
 * Moerover, it may be preferable instead to implement another interface
 * such as {@link java.util.JumpableRng} or {@link java.util.LeapableRng},
 * or to extend an abstract class such as {@link java.util.AbstractSplittableRng}
 * or {@link java.util.AbstractArbitrarilyJumpableRng}.
 *
 * <p>Objects that implement {@code java.util.Rng} are typically
 * not cryptographically secure.  Consider instead using
 * {@link java.security.SecureRandom} to get a cryptographically
 * secure pseudorandom number generator for use by
 * security-sensitive applications.  Note, however, that
 * {@code java.security.SecureRandom} does implement the {@code Rng}
 * interface, so that instances of {@code java.security.SecureRandom}
 * may be used interchangeably with other types of pseudorandom
 * generators in applications that do not require a secure generator.
 *
 * @author  Guy Steele
 * @since   1.9
 */

interface Rng {

    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code double} values.
     *
     * @implNote It is permitted to implement this method in a manner
     * equivalent to {@code doubles(Long.MAX_VALUE)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextDouble()}.
     *
     * @return a stream of pseudorandomly chosen {@code double} values
     */

    default DoubleStream doubles() {
        return DoubleStream.generate(this::nextDouble).sequential();
    }

    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code double} values, where each value is between the specified
     * origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote It is permitted to implement this method in a manner
     *           equivalent to 
     * {@code doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextDouble(randomNumberOrigin, randomNumberBound)}.
     *
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code double} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
        return DoubleStream.generate(() -> nextDouble(randomNumberOrigin, randomNumberBound)).sequential();
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code double} values.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextDouble()}.
     *
     * @param streamSize the number of values to generate
     * @return a stream of pseudorandomly chosen {@code double} values
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero
     */
    default DoubleStream doubles(long streamSize) {
	RngSupport.checkStreamSize(streamSize);
	return doubles().limit(streamSize);
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code double} values, where each value is between
     * the specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextDouble(randomNumberOrigin, randomNumberBound)}.
     *
     * @param streamSize the number of values to generate
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code double} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero, or {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default DoubleStream doubles(long streamSize, double randomNumberOrigin,
			  double randomNumberBound) {
	RngSupport.checkStreamSize(streamSize);
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
	return doubles(randomNumberOrigin, randomNumberBound).limit(streamSize);
    }
   
    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code int} values.
     *
     * @implNote It is permitted to implement this method in a manner
     * equivalent to {@code ints(Long.MAX_VALUE)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextInt()}.
     *
     * @return a stream of pseudorandomly chosen {@code int} values
     */

    default IntStream ints() {
        return IntStream.generate(this::nextInt).sequential();
    }

    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code int} values, where each value is between the specified
     * origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote It is permitted to implement this method in a manner
     *           equivalent to 
     * {@code ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextInt(randomNumberOrigin, randomNumberBound)}.
     *
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code int} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default IntStream ints(int randomNumberOrigin, int randomNumberBound) {
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
        return IntStream.generate(() -> nextInt(randomNumberOrigin, randomNumberBound)).sequential();
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code int} values.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextInt()}.
     *
     * @param streamSize the number of values to generate
     * @return a stream of pseudorandomly chosen {@code int} values
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero
     */
    default IntStream ints(long streamSize) {
	RngSupport.checkStreamSize(streamSize);
	return ints().limit(streamSize);
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code int} values, where each value is between
     * the specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextInt(randomNumberOrigin, randomNumberBound)}.
     *
     * @param streamSize the number of values to generate
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code int} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero, or {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default IntStream ints(long streamSize, int randomNumberOrigin,
			  int randomNumberBound) {
	RngSupport.checkStreamSize(streamSize);
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
	return ints(randomNumberOrigin, randomNumberBound).limit(streamSize);
    }

    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code long} values.
     *
     * @implNote It is permitted to implement this method in a manner
     * equivalent to {@code longs(Long.MAX_VALUE)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextLong()}.
     *
     * @return a stream of pseudorandomly chosen {@code long} values
     */

    default LongStream longs() {
        return LongStream.generate(this::nextLong).sequential();
    }

    /**
     * Returns an effectively unlimited stream of pseudorandomly chosen
     * {@code long} values, where each value is between the specified
     * origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote It is permitted to implement this method in a manner
     *           equivalent to 
     * {@code longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextLong(randomNumberOrigin, randomNumberBound)}.
     *
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code long} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default LongStream longs(long randomNumberOrigin, long randomNumberBound) {
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
        return LongStream.generate(() -> nextLong(randomNumberOrigin, randomNumberBound)).sequential();
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code long} values.
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextLong()}.
     *
     * @param streamSize the number of values to generate
     * @return a stream of pseudorandomly chosen {@code long} values
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero
     */
    default LongStream longs(long streamSize) {
	RngSupport.checkStreamSize(streamSize);
	return longs().limit(streamSize);
    }

    /**
     * Returns a stream producing the given {@code streamSize} number of
     * pseudorandomly chosen {@code long} values, where each value is between
     * the specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation produces a sequential stream
     * that repeatedly calls {@code nextLong(randomNumberOrigin, randomNumberBound)}.
     *
     * @param streamSize the number of values to generate
     * @param randomNumberOrigin the least value that can be produced
     * @param randomNumberBound the upper bound (exclusive) for each value produced
     * @return a stream of pseudorandomly chosen {@code long} values, each between
     *         the specified origin (inclusive) and the specified bound (exclusive)
     * @throws IllegalArgumentException if {@code streamSize} is
     *         less than zero, or {@code randomNumberOrigin}
     *         is greater than or equal to {@code randomNumberBound}
     */
    default LongStream longs(long streamSize, long randomNumberOrigin,
			  long randomNumberBound) {
	RngSupport.checkStreamSize(streamSize);
	RngSupport.checkRange(randomNumberOrigin, randomNumberBound);
	return longs(randomNumberOrigin, randomNumberBound).limit(streamSize);
    }

    /**
     * Returns a pseudorandomly chosen {@code boolean} value.
     *
     * <p>The default implementation tests the high-order bit (sign bit)
     * of a value produced by {@code nextInt()}, on the grounds
     * that some algorithms for pseudorandom number generation
     * produce values whose high-order bits have better
     * statistical quality than the low-order bits.
     *
     * @return a pseudorandomly chosen {@code boolean} value
     */
    default boolean nextBoolean() {
        return nextInt() < 0;
    }

    /**
     * Returns a pseudorandom {@code float} value between zero
     * (inclusive) and one (exclusive).
     *
     * The default implementation uses the 24 high-order bits
     * from a call to {@code nextInt()}.
     *
     * @return a pseudorandom {@code float} value between zero
     *         (inclusive) and one (exclusive)
     */
    default float nextFloat() {
        return (nextInt() >>> 8) * 0x1.0p-24f;
    }

    /**
     * Returns a pseudorandomly chosen {@code float} value between zero
     * (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkBound(bound)} and then
     *     {@code RngSupport.boundedNextFloat(this, bound)}.
     *
     * @param bound the upper bound (exclusive) for the returned value.
     *        Must be positive and finite
     * @return a pseudorandomly chosen {@code float} value between
     *         zero (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code bound} is not
     *         positive and finite
     */
    default float nextFloat(float bound) {
	RngSupport.checkBound(bound);
	return RngSupport.boundedNextFloat(this, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code float} value between the
     * specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkRange(origin, bound)} and then
     *     {@code RngSupport.boundedNextFloat(this, origin, bound)}.
     *
     * @param origin the least value that can be returned
     * @param bound the upper bound (exclusive)
     * @return a pseudorandomly chosen {@code float} value between the
     *         origin (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException unless {@code origin} is finite,
     *         {@code bound} is finite, and {@code origin} is less than
     *         {@code bound}
     */
    default float nextFloat(float origin, float bound) {
	RngSupport.checkRange(origin, bound);
        return RngSupport.boundedNextFloat(this, origin, bound);
    }

    /**
     * Returns a pseudorandom {@code double} value between zero
     * (inclusive) and one (exclusive).
     *
     * The default implementation uses the 53 high-order bits
     * from a call to {@code nextLong()}.
     *
     * @return a pseudorandom {@code double} value between zero
     *         (inclusive) and one (exclusive)
     */
    default double nextDouble() {
        return (nextLong() >>> 11) * 0x1.0p-53;
    }

    /**
     * Returns a pseudorandomly chosen {@code double} value between zero
     * (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkBound(bound)} and then
     *     {@code RngSupport.boundedNextDouble(this, bound)}.
     *
     * @param bound the upper bound (exclusive) for the returned value.
     *        Must be positive and finite
     * @return a pseudorandomly chosen {@code double} value between
     *         zero (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code bound} is not
     *         positive and finite
     */
    default double nextDouble(double bound) {
	RngSupport.checkBound(bound);
	return RngSupport.boundedNextDouble(this, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code double} value between the
     * specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkRange(origin, bound)} and then
     *     {@code RngSupport.boundedNextDouble(this, origin, bound)}.
     *
     * @param origin the least value that can be returned
     * @param bound the upper bound (exclusive) for the returned value
     * @return a pseudorandomly chosen {@code double} value between the
     *         origin (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException unless {@code origin} is finite,
     *         {@code bound} is finite, and {@code origin} is less than
     *         {@code bound}
     */
    default double nextDouble(double origin, double bound) {
	RngSupport.checkRange(origin, bound);
        return RngSupport.boundedNextDouble(this, origin, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code int} value.
     *
     * The default implementation uses the 32 high-order bits
     * from a call to {@code nextLong()}.
     *
     * @return a pseudorandomly chosen {@code int} value
     */
    default public int nextInt() {
	return (int)(nextLong() >>> 32);
    }

    /**
     * Returns a pseudorandomly chosen {@code int} value between
     * zero (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkBound(bound)} and then
     *     {@code RngSupport.boundedNextInt(this, bound)}.
     *
     * @param bound the upper bound (exclusive) for the returned value.  Must be positive.
     * @return a pseudorandomly chosen {@code int} value between
     *         zero (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code bound} is not positive
     */
    default int nextInt(int bound) {
	RngSupport.checkBound(bound);
	return RngSupport.boundedNextInt(this, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code int} value between the
     * specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkRange(origin, bound)} and then
     *     {@code RngSupport.boundedNextInt(this, origin, bound)}.
     *
     * @param origin the least value that can be returned
     * @param bound the upper bound (exclusive) for the returned value
     * @return a pseudorandomly chosen {@code int} value between the
     *         origin (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code origin} is greater than
     *         or equal to {@code bound}
     */
    default int nextInt(int origin, int bound) {
	RngSupport.checkRange(origin, bound);
        return RngSupport.boundedNextInt(this, origin, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code long} value.
     *
     * @return a pseudorandomly chosen {@code long} value
     */
    long nextLong();

    /**
     * Returns a pseudorandomly chosen {@code long} value between
     * zero (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkBound(bound)} and then
     *     {@code RngSupport.boundedNextLong(this, bound)}.
     *
     * @param bound the upper bound (exclusive) for the returned value.  Must be positive.
     * @return a pseudorandomly chosen {@code long} value between
     *         zero (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code bound} is not positive
     */
    default long nextLong(long bound) {
	RngSupport.checkBound(bound);
	return RngSupport.boundedNextLong(this, bound);
    }

    /**
     * Returns a pseudorandomly chosen {@code long} value between the
     * specified origin (inclusive) and the specified bound (exclusive).
     *
     * @implNote The default implementation simply calls
     *     {@code RngSupport.checkRange(origin, bound)} and then
     *     {@code RngSupport.boundedNextInt(this, origin, bound)}.
     *
     * @param origin the least value that can be returned
     * @param bound the upper bound (exclusive) for the returned value
     * @return a pseudorandomly chosen {@code long} value between the
     *         origin (inclusive) and the bound (exclusive)
     * @throws IllegalArgumentException if {@code origin} is greater than
     *         or equal to {@code bound}
     */
    default long nextLong(long origin, long bound) {
	RngSupport.checkRange(origin, bound);
        return RngSupport.boundedNextLong(this, origin, bound);
    }
    
    /**
     * Returns a {@code double} value pseudorandomly chosen from
     * a Gaussian (normal) distribution whose mean is 0 and whose
     * standard deviation is 1.
     *
     * @return a {@code double} value pseudorandomly chosen from a
     *         Gaussian distribution
     */
    default double nextGaussian() {
	return RngSupport.computeNextGaussian(this);
    }

    /**
     * Returns a {@code double} value pseudorandomly chosen from
     * a Gaussian (normal) distribution with a mean and
     * standard deviation specified by the arguments.
     *
     * @param mean the mean of the Gaussian distribution to be drawn from
     * @param stddev the standard deviation of the Gaussian distribution to be drawn from
     * @return a {@code double} value pseudorandomly chosen from the
     *         specified Gaussian distribution
     */
    default double nextGaussian(double mean, double stddev) {
	return mean + RngSupport.computeNextGaussian(this) * stddev * stddev;
    }

    /**
     * Returns a nonnegative {@code double} value pseudorandomly chosen
     * from an exponential distribution whose mean is 1.
     *
     * @return a nonnegative {@code double} value pseudorandomly chosen from an
     *         exponential distribution
     */
    default double nextExponential() {
	return RngSupport.computeNextExponential(this);
    }

    
    /**
     * Returns the period of this {@code Rng} object.
     *
     * @return a {@code BigInteger} whose value is the number of
     *         distinct possible states of this {@code Rng} object,
     *         or 0 if unknown, or negative if extremely large.
     */
    BigInteger period();

    /**
     * The value (0) returned by the {@code period()} method if the period is unknown.
     */
    static final BigInteger UNKNOWN_PERIOD = BigInteger.ZERO;

    /**
     * The (negative) value returned by the {@code period()} method if this generator
     * has no period because it is truly random rather than just pseudorandom.
     */
    static final BigInteger TRULY_RANDOM = BigInteger.valueOf(-1);

    /**
     * The (negative) value that may be returned by the {@code period()} method
     * if this generator has a huge period (larger than 2**(2**16)).
     */
    static final BigInteger HUGE_PERIOD = BigInteger.valueOf(-2);
}