diff -r b0c958c0e6c6 -r f02ffcb61dce src/java.base/share/classes/java/util/random/RandomNumberGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/util/random/RandomNumberGenerator.java Thu Jun 27 18:30:27 2019 -0300 @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.random; + +import java.math.BigInteger; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +/** + * The {@link RandomNumberGenerator} 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. + *

+ * 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. + *

+ * In the case of {@code int}, {@code long}, and {@link 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 + * 2w values between 0.0 (inclusive) and 1.0 (exclusive), where w is 23 for + * {@code float} values and 52 for {@code double} values, such that adjacent values differ by + * 2w; 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. + *

+ * 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 {@link RandomNumberGenerator}, 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. + *

+ * Every object that implements the {@link RandomNumberGenerator} 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 + * period. (Some implementations of the {@link RandomNumberGenerator} 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.) + *

+ * As a rule, objects that implement the {@link RandomNumberGenerator} interface need not be + * thread-safe. It is recommended that multithreaded applications use either {@link + * ThreadLocalRandom} or (preferably) pseudorandom number generators that implement the {@link + * SplittableRNG} or {@link 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 JumpableRNG} or {@link LeapableRNG}, or to extend an abstract + * class such as {@link AbstractSplittableRNG} or {@link AbstractArbitrarilyJumpableRNG}. + *

+ * Objects that implement {@link RandomNumberGenerator} 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 {@link RandomNumberGenerator} 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. + * + * @since 14 + */ +public interface RandomNumberGenerator { + + /** + * Returns an effectively unlimited stream of pseudorandomly chosen + * {@code double} values. + * + * @return a 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()}. + */ + 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). + * + * @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} + * + * @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)}. + */ + 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. + * + * @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 + * + * @implNote The default implementation produces a sequential stream + * that repeatedly calls {@code nextDouble()}. + */ + 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). + * + * @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} + * + * @implNote The default implementation produces a sequential stream + * that repeatedly calls {@code nextDouble(randomNumberOrigin, 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. + * + * @return a 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()}. + */ + 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). + * + * @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} + * + * @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)}. + */ + 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. + * + * @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 + * + * @implNote The default implementation produces a sequential stream + * that repeatedly calls {@code nextInt()}. + */ + 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). + * + * @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} + * + * @implNote The default implementation produces a sequential stream that repeatedly + * calls {@code nextInt(randomNumberOrigin, 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. + * + * @return a 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()}. + */ + 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). + * + * @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} + * + * @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)}. + */ + 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. + * + * @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 + * + * @implNote The default implementation produces a sequential stream + * that repeatedly calls {@code nextLong()}. + */ + 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). + * + * @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} + * + * @implNote The default implementation produces a sequential stream that repeatedly + * calls {@code nextLong(randomNumberOrigin, 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. + *

+ * 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). + * + * @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 + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkBound(bound)} and then + * {@code RNGSupport.boundedNextFloat(this, bound)}. + */ + 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). + * + * @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} + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkRange(origin, bound)} and then + * {@code RNGSupport.boundedNextFloat(this, origin, 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). + * + * @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 + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkBound(bound)} and then + * {@code RNGSupport.boundedNextDouble(this, bound)}. + */ + 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). + * + * @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} + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkRange(origin, bound)} and then + * {@code RNGSupport.boundedNextDouble(this, origin, 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). + * + * @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 + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkBound(bound)} and then + * {@code RNGSupport.boundedNextInt(this, bound)}. + */ + 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). + * + * @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} + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkRange(origin, bound)} and then + * {@code RNGSupport.boundedNextInt(this, origin, 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). + * + * @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 + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkBound(bound)} and then + * {@code RNGSupport.boundedNextLong(this, bound)}. + */ + 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). + * + * @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} + * + * @implNote The default implementation simply calls + * {@code RNGSupport.checkRange(origin, bound)} and then + * {@code RNGSupport.boundedNextInt(this, origin, 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 (square root of the variance) + * of the Gaussian distribution to be drawn from + * + * @return a {@code double} value pseudorandomly chosen from the + * specified Gaussian distribution + * + * @throws IllegalArgumentException if {@code stddev} is negative + */ + default double nextGaussian(double mean, double stddev) { + if (stddev < 0.0) throw new IllegalArgumentException("standard deviation must be non-negative"); + return mean + stddev * RNGSupport.computeNextGaussian(this); + } + + /** + * 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 {@link RandomNumberGenerator} object. + * + * @return a {@link BigInteger} whose value is the number of distinct possible states of this + * {@link RandomNumberGenerator} 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); +}