mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8279598: Provide adapter from RandomGenerator to Random
Reviewed-by: smarks, darcy
This commit is contained in:
parent
497a94fead
commit
df8c2be5fe
3 changed files with 247 additions and 25 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2022, 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
|
||||
|
@ -31,6 +31,7 @@ import java.util.random.RandomGenerator;
|
|||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
import jdk.internal.util.random.RandomSupport.*;
|
||||
|
||||
import static jdk.internal.util.random.RandomSupport.*;
|
||||
|
@ -82,6 +83,164 @@ import jdk.internal.misc.Unsafe;
|
|||
equidistribution = 0
|
||||
)
|
||||
public class Random implements RandomGenerator, java.io.Serializable {
|
||||
|
||||
/**
|
||||
* Class used to wrap a {@link java.util.random.RandomGenerator} to
|
||||
* {@link java.util.Random}.
|
||||
*/
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static final class RandomWrapper extends Random implements RandomGenerator {
|
||||
private final RandomGenerator generator;
|
||||
//randomToWrap must never be null
|
||||
private RandomWrapper(RandomGenerator randomToWrap) {
|
||||
super(null);
|
||||
this.generator = randomToWrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@code NotSerializableException}.
|
||||
*
|
||||
* @param s the object input stream
|
||||
* @throws NotSerializableException always
|
||||
*/
|
||||
@Serial
|
||||
private void readObject(ObjectInputStream s) throws NotSerializableException {
|
||||
throw new NotSerializableException("not serializable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@code NotSerializableException}.
|
||||
*
|
||||
* @param s the object output stream
|
||||
* @throws NotSerializableException always
|
||||
*/
|
||||
@Serial
|
||||
private void writeObject(ObjectOutputStream s) throws NotSerializableException {
|
||||
throw new NotSerializableException("not serializable");
|
||||
}
|
||||
|
||||
/**
|
||||
* setSeed does not exist in {@link java.util.random.RandomGenerator} so can't
|
||||
* use it.
|
||||
*/
|
||||
@Override
|
||||
public void setSeed(long seed) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
this.generator.nextBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt() {
|
||||
return this.generator.nextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt(int bound) {
|
||||
return this.generator.nextInt(bound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextLong() {
|
||||
return this.generator.nextLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextBoolean() {
|
||||
return this.generator.nextBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float nextFloat() {
|
||||
return this.generator.nextFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double nextDouble() {
|
||||
return this.generator.nextDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double nextGaussian() {
|
||||
return this.generator.nextGaussian();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntStream ints(long streamSize) {
|
||||
return this.generator.ints(streamSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntStream ints() {
|
||||
return this.generator.ints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) {
|
||||
return this.generator.ints(streamSize, randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
|
||||
return this.generator.ints(randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongStream longs(long streamSize) {
|
||||
return this.generator.longs(streamSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongStream longs() {
|
||||
return this.generator.longs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongStream longs(long streamSize, long randomNumberOrigin, long randomNumberBound) {
|
||||
return this.generator.longs(streamSize, randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
|
||||
return this.generator.longs(randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleStream doubles(long streamSize) {
|
||||
return this.generator.doubles(streamSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleStream doubles() {
|
||||
return this.generator.doubles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
|
||||
return this.generator.doubles(streamSize, randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
|
||||
return this.generator.doubles(randomNumberOrigin, randomNumberBound);
|
||||
}
|
||||
|
||||
//This method should never be reached unless done by reflection so we should throw when tried
|
||||
@Override
|
||||
protected int next(int bits) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RandomWrapper[" + generator + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.1 for interoperability */
|
||||
@java.io.Serial
|
||||
static final long serialVersionUID = 3905348978240129619L;
|
||||
|
@ -108,6 +267,10 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
|||
this(seedUniquifier() ^ System.nanoTime());
|
||||
}
|
||||
|
||||
private Random(Void unused) {
|
||||
this.seed = null;
|
||||
}
|
||||
|
||||
private static long seedUniquifier() {
|
||||
// L'Ecuyer, "Tables of Linear Congruential Generators of
|
||||
// Different Sizes and Good Lattice Structure", 1999
|
||||
|
@ -151,23 +314,40 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the seed of this random number generator using a single
|
||||
* {@code long} seed. The general contract of {@code setSeed} is
|
||||
* that it alters the state of this random number generator object
|
||||
* so as to be in exactly the same state as if it had just been
|
||||
* created with the argument {@code seed} as a seed. The method
|
||||
* {@code setSeed} is implemented by class {@code Random} by
|
||||
* atomically updating the seed to
|
||||
* Returns an instance of {@code Random} that delegates method calls to the {@link RandomGenerator}
|
||||
* argument. If the generator is an instance of {@code Random}, it is returned. Otherwise, this method
|
||||
* returns an instance of {@code Random} that delegates all methods except {@code setSeed} to the generator.
|
||||
* The returned instance's {@code setSeed} method always throws {@link UnsupportedOperationException}.
|
||||
* The returned instance is not serializable.
|
||||
*
|
||||
* @param generator the {@code RandomGenerator} calls are delegated to
|
||||
* @return the delegating {@code Random} instance
|
||||
* @throws NullPointerException if generator is null
|
||||
* @since 19
|
||||
*/
|
||||
public static Random from(RandomGenerator generator) {
|
||||
Objects.requireNonNull(generator);
|
||||
if (generator instanceof Random rand)
|
||||
return rand;
|
||||
|
||||
return new RandomWrapper(generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or updates the seed of this random number generator using the
|
||||
* provided {@code long} seed value (optional operation).
|
||||
*
|
||||
* @implSpec
|
||||
* The implementation in this class alters the state of this random number
|
||||
* generator so that it is in the same state as if it had just been created with
|
||||
* {@link #Random(long) new Random(seed)}. It atomically updates the seed to
|
||||
* <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
|
||||
* and clearing the {@code haveNextNextGaussian} flag used by {@link
|
||||
* #nextGaussian}.
|
||||
* and clears the {@code haveNextNextGaussian} flag used by {@link #nextGaussian}.
|
||||
* Note that this uses only 48 bits of the given seed value.
|
||||
*
|
||||
* <p>The implementation of {@code setSeed} by class {@code Random}
|
||||
* happens to use only 48 bits of the given seed. In general, however,
|
||||
* an overriding method may use all 64 bits of the {@code long}
|
||||
* argument as a seed value.
|
||||
*
|
||||
* @param seed the initial seed
|
||||
* @param seed the seed value
|
||||
* @throws UnsupportedOperationException if the {@code setSeed}
|
||||
* operation is not supported by this random number generator
|
||||
*/
|
||||
public synchronized void setSeed(long seed) {
|
||||
this.seed.set(initialScramble(seed));
|
||||
|
@ -175,21 +355,26 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generates the next pseudorandom number. Subclasses should
|
||||
* override this, as this is used by all other methods.
|
||||
*
|
||||
* <p>The general contract of {@code next} is that it returns an
|
||||
* {@code int} value and if the argument {@code bits} is between
|
||||
* Generates the next pseudorandom number. This method returns an
|
||||
* {@code int} value such that, if the argument {@code bits} is between
|
||||
* {@code 1} and {@code 32} (inclusive), then that many low-order
|
||||
* bits of the returned value will be (approximately) independently
|
||||
* chosen bit values, each of which is (approximately) equally
|
||||
* likely to be {@code 0} or {@code 1}. The method {@code next} is
|
||||
* implemented by class {@code Random} by atomically updating the seed to
|
||||
* likely to be {@code 0} or {@code 1}.
|
||||
*
|
||||
* @apiNote
|
||||
* The other random-producing methods in this class are implemented
|
||||
* in terms of this method, so subclasses can override just this
|
||||
* method to provide a different source of pseudorandom numbers for
|
||||
* the entire class.
|
||||
*
|
||||
* @implSpec
|
||||
* The implementation in this class atomically updates the seed to
|
||||
* <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
|
||||
* and returning
|
||||
* and returns
|
||||
* <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
|
||||
*
|
||||
* This is a linear congruential pseudorandom number generator, as
|
||||
* <p>This is a linear congruential pseudorandom number generator, as
|
||||
* defined by D. H. Lehmer and described by Donald E. Knuth in
|
||||
* <cite>The Art of Computer Programming, Volume 2, Third edition:
|
||||
* Seminumerical Algorithms</cite>, section 3.2.1.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue