8330005: RandomGeneratorFactory.getDefault() throws exception when the runtime image only has java.base module

Reviewed-by: jpai, alanb
This commit is contained in:
Raffaello Giulietti 2024-05-08 08:27:13 +00:00
parent 2baacfc169
commit 7f299043a9
14 changed files with 38 additions and 104 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, 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
@ -142,8 +142,9 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return Map of RandomGeneratorFactory classes.
*/
private static Map<String, Provider<? extends RandomGenerator>> createFactoryMap() {
FactoryMapHolder.class.getModule().addUses(RandomGenerator.class);
return ServiceLoader
.load(RandomGenerator.class)
.load(RandomGenerator.class, ClassLoader.getPlatformClassLoader())
.stream()
.filter(p -> !p.type().isInterface())
.collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity()));
@ -341,9 +342,6 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* {@link RandomGenerator} that utilize the {@code name}
* <a href="package-summary.html#algorithms">algorithm</a>.
*
* @implSpec Availability is determined by RandomGeneratorFactory using the
* service provider API to locate implementations of the RandomGenerator interface.
*
* @param name Name of random number generator
* <a href="package-summary.html#algorithms">algorithm</a>
* @param <T> Sub-interface of {@link RandomGenerator} to produce
@ -376,12 +374,9 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
/**
* Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
*
* <p>
* RandomGenerators that are marked as deprecated are not included in the result.
*
* @implSpec Availability is determined by RandomGeneratorFactory using the service provider API
* to locate implementations of the RandomGenerator interface.
*
* @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
*/
public static Stream<RandomGeneratorFactory<RandomGenerator>> all() {
@ -615,5 +610,3 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, 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
@ -50,9 +50,7 @@
* <p> The principal supporting class is {@link RandomGeneratorFactory}. This
* can be used to generate multiple random number generators for a specific
* algorithm. {@link RandomGeneratorFactory} also provides methods for
* selecting random number generator algorithms. RandomGeneratorFactory
* registers implementations of {@link RandomGenerator} interface using the
* service provider API.
* selecting random number generator algorithms.
*
* <p> An important subsidiary interface is
* {@link RandomGenerator.StreamableGenerator}, which provides methods for
@ -636,4 +634,3 @@
* @since 17
*/
package java.util.random;

View file

@ -0,0 +1,338 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>1152</sup>. Class {@link L128X1024MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L128X1024MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L128X1024MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L128X1024MixRandom}
* has 1152 bits of state plus one 128-bit instance-specific parameter.
*
* <p>If two instances of {@link L128X1024MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L128X1024MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL128X1024MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L128X1024MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L128X1024MixRandom",
group = "LXM",
i = 1024, j = 1, k = 128,
equidistribution = 1
)
public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The 128-bit parameter `a` is represented as two long fields `ah` and `al`.
* The 128-bit state variable `s` is represented as two long fields `sh` and `sl`.
*
* The split operation uses the current generator to choose 20
* new 64-bit long values that are then used to initialize the
* parameters `ah` and `al`, the state variables `sh`, `sl`,
* and the array `x` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L128X1024MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate 20 new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/*
* The length of the array x.
*/
private static final int N = 16;
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Low half of multiplier used in the LCG portion of the algorithm;
* the overall multiplier is (2**64 + ML).
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0x1d605bbb58c8abbfdLL
* are [0.991889, 0.907938, 0.830964, 0.837980, 0.780378, 0.797464, 0.761493].
*/
private static final long ML = 0xd605bbb58c8abbfdL;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd (therefore al must be odd).
*/
private final long ah, al;
/**
* The per-instance state: sh and sl for the LCG; the array x for the XBG;
* p is the rotating pointer into the array x.
* At least one of the 16 elements of the array x must be nonzero.
*/
private long sh, sl;
private final long[] x;
private int p = N - 1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param ah high half of the additive parameter for the LCG
* @param al low half of the additive parameter for the LCG
* @param sh high half of the initial state for the LCG
* @param sl low half of the initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
* @param x2 third word of the initial state for the XBG
* @param x3 fourth word of the initial state for the XBG
* @param x4 fifth word of the initial state for the XBG
* @param x5 sixth word of the initial state for the XBG
* @param x6 seventh word of the initial state for the XBG
* @param x7 eight word of the initial state for the XBG
* @param x8 ninth word of the initial state for the XBG
* @param x9 tenth word of the initial state for the XBG
* @param x10 eleventh word of the initial state for the XBG
* @param x11 twelfth word of the initial state for the XBG
* @param x12 thirteenth word of the initial state for the XBG
* @param x13 fourteenth word of the initial state for the XBG
* @param x14 fifteenth word of the initial state for the XBG
* @param x15 sixteenth word of the initial state for the XBG
*/
public L128X1024MixRandom(long ah, long al, long sh, long sl,
long x0, long x1, long x2, long x3,
long x4, long x5, long x6, long x7,
long x8, long x9, long x10, long x11,
long x12, long x13, long x14, long x15) {
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x = new long[N];
this.x[0] = x0;
this.x[1] = x1;
this.x[2] = x2;
this.x[3] = x3;
this.x[4] = x4;
this.x[5] = x5;
this.x[6] = x6;
this.x[7] = x7;
this.x[8] = x8;
this.x[9] = x9;
this.x[10] = x10;
this.x[11] = x11;
this.x[12] = x12;
this.x[13] = x13;
this.x[14] = x14;
this.x[15] = x15;
// If x0, x1, ..., x15 are all zero (very unlikely), we must choose nonzero values.
if ((x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15) == 0) {
long v = sh;
// At least fifteen of the sixteen values generated here will be nonzero.
for (int j = 0; j < N; j++) {
this.x[j] = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
}
}
}
/**
* Creates a new instance of {@link L128X1024MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L128X1024MixRandom} created with the same seed in the same
* program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X1024MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x[0]`,
// which will then be used to produce the first generated value.
// The other x values are filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
RandomSupport.mixMurmur64(seed += RandomSupport.GOLDEN_RATIO_64),
0,
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X1024MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L128X1024MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X1024MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L128X1024MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X1024MixRandom(byte[] seed) {
// Convert the seed to 20 long values, of which the last 16 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 20, 16);
long ah = data[0], al = data[1], sh = data[2], sl = data[3];
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x = new long[N];
for (int j = 0; j < N; j++) {
this.x[j] = data[4+j];
}
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for (the low half of) `a`.
return new L128X1024MixRandom(source.nextLong(), brine << 1,
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// First part of xoroshiro1024: fetch array data
final int q = p;
final long s0 = x[p = (p + 1) & (N - 1)];
long s15 = x[q];
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(sh + s0);
// Update the LCG subgenerator
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
final long u = ML * sl;
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
sl = u + al;
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
// Second part of xoroshiro1024: update array data
s15 ^= s0;
x[q] = Long.rotateLeft(s0, 25) ^ s15 ^ (s15 << 27);
x[p] = Long.rotateLeft(s15, 36);
return result;
}
}

View file

@ -0,0 +1,268 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>256</sup>. Class {@link L128X128MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L128X128MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L128X128MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L128X128MixRandom}
* has 256 bits of state plus one 128-bit instance-specific parameter.
*
* <p>If two instances of {@link L128X128MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L128X128MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL128X128MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L128X128MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L128X128MixRandom",
group = "LXM",
i = 128, j = 1, k = 128,
equidistribution = 1
)
public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split operation uses the current generator to choose four new 64-bit
* long values that are then used to initialize the parameter `a` and the
* state variables `s`, `x0`, and `x1` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L128X128MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate four new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Low half of multiplier used in the LCG portion of the algorithm;
* the overall multiplier is (2**64 + ML).
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0x1d605bbb58c8abbfdLL
* are [0.991889, 0.907938, 0.830964, 0.837980, 0.780378, 0.797464, 0.761493].
*/
private static final long ML = 0xd605bbb58c8abbfdL;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd (therefore al must be odd).
*/
private final long ah, al;
/**
* The per-instance state: sh and sl for the LCG; x0 and x1 for the XBG.
* At least one of x0 and x1 must be nonzero.
*/
private long sh, sl, x0, x1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param ah high half of the additive parameter for the LCG
* @param al low half of the additive parameter for the LCG
* @param sh high half of the initial state for the LCG
* @param sl low half of the initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
*/
public L128X128MixRandom(long ah, long al, long sh, long sl, long x0, long x1) {
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x0 = x0;
this.x1 = x1;
// If x0 and x1 are both zero, we must choose nonzero values.
if ((x0 | x1) == 0) {
long v = sh;
// At least one of the two values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x1 = RandomSupport.mixStafford13(v + RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link L128X128MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L128X128MixRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X128MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// Then x1 is filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
RandomSupport.mixMurmur64(seed += RandomSupport.GOLDEN_RATIO_64),
0,
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X128MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L128X128MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X128MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L128X128MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X128MixRandom(byte[] seed) {
// Convert the seed to 6 long values, of which the last 2 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 2);
long ah = data[0], al = data[1], sh = data[2], sl = data[3], x0 = data[4], x1 = data[5];
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x0 = x0;
this.x1 = x1;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for (the low half of) `a`.
return new L128X128MixRandom(source.nextLong(), brine << 1,
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(sh + x0);
// Update the LCG subgenerator
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
final long u = ML * sl;
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
sl = u + al;
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
long q0 = x0, q1 = x1;
// Update the XBG subgenerator
{ // xoroshiro128v1_0
q1 ^= q0;
q0 = Long.rotateLeft(q0, 24);
q0 = q0 ^ q1 ^ (q1 << 16);
q1 = Long.rotateLeft(q1, 37);
}
x0 = q0; x1 = q1;
return result;
}
}

View file

@ -0,0 +1,292 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>384</sup>. Class {@link L128X256MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L128X256MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L128X256MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L128X256MixRandom}
* has 384 bits of state plus one 128-bit instance-specific parameter.
*
* <p>If two instances of {@link L128X256MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L128X256MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL128X256MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L128X256MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L128X256MixRandom",
group = "LXM",
i = 256, j = 1, k = 128,
equidistribution = 1
)
public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The 128-bit parameter `a` is represented as two long fields `ah` and `al`.
* The 128-bit state variable `s` is represented as two long fields `sh` and `sl`.
*
* The split operation uses the current generator to choose eight
* new 64-bit long values that are then used to initialize the
* parameters `ah` and `al` and the state variables `sh`, `sl`,
* `x0`, `x1`, `x2`, and `x3` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L128X256MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate eight new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* The equidistribution of the algorithm.
*/
private static final int EQUIDISTRIBUTION = 1;
/*
* Low half of multiplier used in the LCG portion of the algorithm;
* the overall multiplier is (2**64 + ML).
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0x1d605bbb58c8abbfdLL
* are [0.991889, 0.907938, 0.830964, 0.837980, 0.780378, 0.797464, 0.761493].
*/
private static final long ML = 0xd605bbb58c8abbfdL;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd (therefore al must be odd).
*/
private final long ah, al;
/**
* The per-instance state: sh and sl for the LCG; x0, x1, x2, and x3 for the XBG.
* At least one of the four fields x0, x1, x2, and x3 must be nonzero.
*/
private long sh, sl, x0, x1, x2, x3;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param ah high half of the additive parameter for the LCG
* @param al low half of the additive parameter for the LCG
* @param sh high half of the initial state for the LCG
* @param sl low half of the initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
* @param x2 third word of the initial state for the XBG
* @param x3 fourth word of the initial state for the XBG
*/
public L128X256MixRandom(long ah, long al, long sh, long sl, long x0, long x1, long x2, long x3) {
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
// If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
if ((x0 | x1 | x2 | x3) == 0) {
long v = sh;
// At least three of the four values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x1 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x2 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x3 = RandomSupport.mixStafford13(v + RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link L128X256MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L128X256MixRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X256MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// The other x values are filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
RandomSupport.mixMurmur64(seed += RandomSupport.GOLDEN_RATIO_64),
0,
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X256MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L128X256MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L128X256MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L128X256MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L128X256MixRandom(byte[] seed) {
// Convert the seed to 8 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 8, 4);
long ah = data[0], al = data[1], sh = data[2], sl = data[3],
x0 = data[4], x1 = data[5], x2 = data[6], x3 = data[7];
// Force a to be odd.
this.ah = ah;
this.al = al | 1;
this.sh = sh;
this.sl = sl;
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for (the low half of) `a`.
return new L128X256MixRandom(source.nextLong(), brine << 1,
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(sh + x0);
// Update the LCG subgenerator
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
final long u = ML * sl;
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
sl = u + al;
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
// Update the XBG subgenerator
long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
{ // xoshiro256 1.0
long t = q1 << 17;
q2 ^= q0;
q3 ^= q1;
q1 ^= q2;
q0 ^= q3;
q2 ^= t;
q3 = Long.rotateLeft(q3, 45);
}
x0 = q0; x1 = q1; x2 = q2; x3 = q3;
return result;
}
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>96</sup>. Class {@link L32X64MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L32X64MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L32X64MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L32X64MixRandom}
* has 96 bits of state plus one 32-bit instance-specific parameter.
*
* <p>If two instances of {@link L32X64MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L32X64MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL32X64MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L32X64MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L32X64MixRandom",
group = "LXM",
i = 64, j = 1, k = 32,
equidistribution = 1
)
public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split operation uses the current generator to choose four new 32-bit
* int values that are then used to initialize the parameter `a` and the
* state variables `s`, `x0`, and `x1` for a newly constructed generator.
*
* With high probability, no two generators so chosen will have the same
* `a` parameter, and testing has indicated that the values generated by
* two instances of {@link L32X64MixRandom} will be (approximately)
* independent if the two instances have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate four new 32-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Multiplier used in the LCG portion of the algorithm.
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0xadb4a92d
* are [0.975884, 0.936244, 0.755793, 0.877642, 0.751300, 0.789333, 0.728869].
*/
private static final int M = 0xadb4a92d;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd.
*/
private final int a;
/**
* The per-instance state: s for the LCG; x0 and x1 for the XBG.
* At least one of x0 and x1 must be nonzero.
*/
private int s, x0, x1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param a additive parameter for the LCG
* @param s initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
*/
public L32X64MixRandom(int a, int s, int x0, int x1) {
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
// If x0 and x1 are both zero, we must choose nonzero values.
if ((x0 | x1) == 0) {
int v = s;
// At least one of the two values generated here will be nonzero.
this.x0 = RandomSupport.mixMurmur32(v += RandomSupport.GOLDEN_RATIO_32);
this.x1 = RandomSupport.mixMurmur32(v + RandomSupport.GOLDEN_RATIO_32);
}
}
/**
* Creates a new instance of {@link L32X64MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L32X64MixRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L32X64MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The high half of the seed is hashed by mixMurmur32 to produce the `a` parameter.
// The low half of the seed is hashed by mixLea32 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// Then x1 is filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_32 as the gamma value and mixLea32 as the mixer.
this(RandomSupport.mixMurmur32((int)((seed ^= RandomSupport.SILVER_RATIO_64) >>> 32)),
1,
RandomSupport.mixLea32((int)(seed)),
RandomSupport.mixLea32((int)(seed) + RandomSupport.GOLDEN_RATIO_32));
}
/**
* Creates a new instance of {@link L32X64MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L32X64MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L32X64MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L32X64MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L32X64MixRandom(byte[] seed) {
// Convert the seed to 4 int values, of which the last 2 are not all zero.
int[] data = RandomSupport.convertSeedBytesToInts(seed, 4, 2);
int a = data[0], s = data[1], x0 = data[2], x1 = data[3];
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use (the low 31 bits of) the brine for `a`.
return new L32X64MixRandom((int)brine << 1, source.nextInt(),
source.nextInt(), source.nextInt());
}
@Override
public int nextInt() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final int result = RandomSupport.mixLea32(s + x0);
// Update the LCG subgenerator
s = M * s + a;
// Update the XBG subgenerator
int q0 = x0, q1 = x1;
{ // xoroshiro64
q1 ^= q0;
q0 = Integer.rotateLeft(q0, 26);
q0 = q0 ^ q1 ^ (q1 << 9);
q1 = Integer.rotateLeft(q1, 13);
}
x0 = q0; x1 = q1;
return result;
}
@Override
public long nextLong() {
return ((long)nextInt() << 32) ^ (long)nextInt();
}
}

View file

@ -0,0 +1,321 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>1088</sup>. Class {@link L64X1024MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L64X1024MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L64X1024MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L64X1024MixRandom}
* has 1088 bits of state plus one 64-bit instance-specific parameter.
*
* <p>If two instances of {@link L64X1024MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L64X1024MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL64X1024MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L64X1024MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L64X1024MixRandom",
group = "LXM",
i = 1024, j = 1, k = 64,
equidistribution = 16
)
public final class L64X1024MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split() operation uses the current generator to choose 18 new 64-bit
* long values that are then used to initialize the parameter `a`, the
* state variable `s`, and the array `x` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L64X1024MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate 18 new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/*
* The length of the array x.
*/
private static final int N = 16;
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Multiplier used in the LCG portion of the algorithm.
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0xd1342543de82ef95
* are [0.958602, 0.937479, 0.870757, 0.822326, 0.820405, 0.813065, 0.760215].
*/
private static final long M = 0xd1342543de82ef95L;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd.
*/
private final long a;
/**
* The per-instance state: s for the LCG; the array x for the XBG;
* p is the rotating pointer into the array x.
* At least one of the 16 elements of the array x must be nonzero.
*/
private long s;
private final long[] x;
private int p = N - 1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param a additive parameter for the LCG
* @param s initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
* @param x2 third word of the initial state for the XBG
* @param x3 fourth word of the initial state for the XBG
* @param x4 fifth word of the initial state for the XBG
* @param x5 sixth word of the initial state for the XBG
* @param x6 seventh word of the initial state for the XBG
* @param x7 eight word of the initial state for the XBG
* @param x8 ninth word of the initial state for the XBG
* @param x9 tenth word of the initial state for the XBG
* @param x10 eleventh word of the initial state for the XBG
* @param x11 twelfth word of the initial state for the XBG
* @param x12 thirteenth word of the initial state for the XBG
* @param x13 fourteenth word of the initial state for the XBG
* @param x14 fifteenth word of the initial state for the XBG
* @param x15 sixteenth word of the initial state for the XBG
*/
public L64X1024MixRandom(long a, long s,
long x0, long x1, long x2, long x3,
long x4, long x5, long x6, long x7,
long x8, long x9, long x10, long x11,
long x12, long x13, long x14, long x15) {
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x = new long[N];
this.x[0] = x0;
this.x[1] = x1;
this.x[2] = x2;
this.x[3] = x3;
this.x[4] = x4;
this.x[5] = x5;
this.x[6] = x6;
this.x[7] = x7;
this.x[8] = x8;
this.x[9] = x9;
this.x[10] = x10;
this.x[11] = x11;
this.x[12] = x12;
this.x[13] = x13;
this.x[14] = x14;
this.x[15] = x15;
// If x0, x1, ..., x15 are all zero (very unlikely), we must choose nonzero values.
if ((x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15) == 0) {
long v = s;
// At least fifteen of the sixteen values generated here will be nonzero.
for (int j = 0; j < N; j++) {
this.x[j] = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
}
}
}
/**
* Creates a new instance of {@link L64X1024MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L64X1024MixRandom} created with the same seed in the same
* program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X1024MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x[0]`,
// which will then be used to produce the first generated value.
// The other x values are filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X1024MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L64X1024MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X1024MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L64X1024MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X1024MixRandom(byte[] seed) {
// Convert the seed to 18 long values, of which the last 16 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 18, 16);
long a = data[0], s = data[1];
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x = new long[N];
for (int j = 0; j < N; j++) {
this.x[j] = data[2+j];
}
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for `a`.
return new L64X1024MixRandom(brine << 1, source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// First part of xoroshiro1024: fetch array data
final int q = p;
final long s0 = x[p = (p + 1) & (N - 1)];
long s15 = x[q];
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(s + s0);
// Update the LCG subgenerator
s = M * s + a; // LCG
// Second part of xoroshiro1024: update array data
s15 ^= s0;
x[q] = Long.rotateLeft(s0, 25) ^ s15 ^ (s15 << 27);
x[p] = Long.rotateLeft(s15, 36);
return result;
}
}

View file

@ -0,0 +1,254 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>192</sup>. Class {@link L64X128MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L64X128MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L64X128MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L64X128MixRandom}
* has 192 bits of state plus one 64-bit instance-specific parameter.
*
* <p>If two instances of {@link L64X128MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L64X128MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL64X128MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L64X128MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L64X128MixRandom",
group = "LXM",
i = 128, j = 1, k = 64,
equidistribution = 2
)
public final class L64X128MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split operation uses the current generator to choose four new 64-bit
* long values that are then used to initialize the parameter `a` and the
* state variables `s`, `x0`, and `x1` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L64X128MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate four new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Multiplier used in the LCG portion of the algorithm.
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0xd1342543de82ef95L
* are [0.958602, 0.937479, 0.870757, 0.822326, 0.820405, 0.813065, 0.760215].
*/
private static final long M = 0xd1342543de82ef95L;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd.
*/
private final long a;
/**
* The per-instance state: s for the LCG; x0 and x1 for the XBG.
* At least one of x0 and x1 must be nonzero.
*/
private long s, x0, x1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param a additive parameter for the LCG
* @param s initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
*/
public L64X128MixRandom(long a, long s, long x0, long x1) {
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
// If x0 and x1 are both zero, we must choose nonzero values.
if ((x0 | x1) == 0) {
long v = s;
// At least one of the two values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x1 = RandomSupport.mixStafford13(v + RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link L64X128MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L64X128MixRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X128MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// Then x1 is filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X128MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L64X128MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X128MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L64X128MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X128MixRandom(byte[] seed) {
// Convert the seed to 4 long values, of which the last 2 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 4, 2);
long a = data[0], s = data[1], x0 = data[2], x1 = data[3];
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for `a`.
return new L64X128MixRandom(brine << 1, source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(s + x0);
// Update the LCG subgenerator
s = M * s + a;
// Update the XBG subgenerator
long q0 = x0, q1 = x1;
{ // xoroshiro128v1_0
q1 ^= q0;
q0 = Long.rotateLeft(q0, 24);
q0 = q0 ^ q1 ^ (q1 << 16);
q1 = Long.rotateLeft(q1, 37);
}
x0 = q0; x1 = q1;
return result;
}
}

View file

@ -0,0 +1,254 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>192</sup>. Class {@link L64X128StarStarRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L64X128StarStarRandom}
* objects or streams of such objects.
*
* <p>The {@link L64X128StarStarRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L64X128StarStarRandom}
* has 192 bits of state plus one 64-bit instance-specific parameter.
*
* <p>If two instances of {@link L64X128StarStarRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L64X128StarStarRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL64X128StarStarRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L64X128StarStarRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L64X128StarStarRandom",
group = "LXM",
i = 128, j = 1, k = 64,
equidistribution = 2
)
public final class L64X128StarStarRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split operation uses the current generator to choose four new 64-bit
* long values that are then used to initialize the parameter `a` and the
* state variables `s`, `x0`, and `x1` for a newly constructed generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L64X128StarStarRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate four new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Multiplier used in the LCG portion of the algorithm.
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0xd1342543de82ef95
* are [0.958602, 0.937479, 0.870757, 0.822326, 0.820405, 0.813065, 0.760215].
*/
private static final long M = 0xd1342543de82ef95L;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd.
*/
private final long a;
/**
* The per-instance state: s for the LCG; x0 and x1 for the XBG.
* At least one of x0 and x1 must be nonzero.
*/
private long s, x0, x1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param a additive parameter for the LCG
* @param s initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
*/
public L64X128StarStarRandom(long a, long s, long x0, long x1) {
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
// If x0 and x1 are both zero, we must choose nonzero values.
if ((x0 | x1) == 0) {
long v = s;
// At least one of the two values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x1 = RandomSupport.mixStafford13(v + RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link L64X128StarStarRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L64X128StarStarRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X128StarStarRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// Then x1 is filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X128StarStarRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L64X128StarStarRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X128StarStarRandom} using the specified array of
* initial seed bytes. Instances of {@link L64X128StarStarRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X128StarStarRandom(byte[] seed) {
// Convert the seed to 4 long values, of which the last 2 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 4, 2);
long a = data[0], s = data[1], x0 = data[2], x1 = data[3];
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for `a`.
return new L64X128StarStarRandom(brine << 1, source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = Long.rotateLeft((s + x0) * 5, 7) * 9; // "starstar" scrambler
// Update the LCG subgenerator
s = M * s + a;
// Update the XBG subgenerator
long q0 = x0, q1 = x1;
{ // xoroshiro128v1_0
q1 ^= q0;
q0 = Long.rotateLeft(q0, 24);
q0 = q0 ^ q1 ^ (q1 << 16);
q1 = Long.rotateLeft(q1, 37);
}
x0 = q0; x1 = q1;
return result;
}
}

View file

@ -0,0 +1,269 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "splittable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>320</sup>. Class {@link L64X256MixRandom} implements
* interfaces {@link RandomGenerator} and {@link SplittableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new split-off {@link L64X256MixRandom}
* objects or streams of such objects.
*
* <p>The {@link L64X256MixRandom} algorithm is a specific member of
* the LXM family of algorithms for pseudorandom number generators;
* for more information, see the documentation for package
* {@link jdk.random}. Each instance of {@link L64X256MixRandom}
* has 320 bits of state plus one 64-bit instance-specific parameter.
*
* <p>If two instances of {@link L64X256MixRandom} are created with
* the same seed within the same program execution, and the same
* sequence of method calls is made for each, they will generate and
* return identical sequences of values.
*
* <p>As with {@link java.util.SplittableRandom}, instances of
* {@link L64X256MixRandom} are <em>not</em> thread-safe. They are
* designed to be split, not shared, across threads (see the {@link #split}
* method). For example, a {@link java.util.concurrent.ForkJoinTask}
* fork/join-style computation using random numbers might include a
* construction of the form
* {@code new Subtask(someL64X256MixRandom.split()).fork()}.
*
* <p>This class provides additional methods for generating random
* streams, that employ the above techniques when used in
* {@code stream.parallel()} mode.
*
* <p>Instances of {@link L64X256MixRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "L64X256MixRandom",
group = "LXM",
i = 256, j = 1, k = 64,
equidistribution = 4
)
public final class L64X256MixRandom extends AbstractSplittableWithBrineGenerator {
/*
* Implementation Overview.
*
* The split operation uses the current generator to choose six new 64-bit
* long values that are then used to initialize the parameter `a` and the
* state variables `s`, `x0`, `x1`, `x2`, and `x3` for a newly constructed
* generator.
*
* With extremely high probability, no two generators so chosen
* will have the same `a` parameter, and testing has indicated
* that the values generated by two instances of {@link L64X256MixRandom}
* will be (approximately) independent if have different values for `a`.
*
* The default (no-argument) constructor, in essence, uses
* "defaultGen" to generate six new 64-bit values for the same
* purpose. Multiple generators created in this way will certainly
* differ in their `a` parameters. The defaultGen state must be accessed
* in a thread-safe manner, so we use an AtomicLong to represent
* this state. To bootstrap the defaultGen, we start off using a
* seed based on current time unless the
* java.util.secureRandomSeed property is set. This serves as a
* slimmed-down (and insecure) variant of SecureRandom that also
* avoids stalls that may occur when using /dev/random.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/*
* Multiplier used in the LCG portion of the algorithm.
* Chosen based on research by Sebastiano Vigna and Guy Steele (2019).
* The spectral scores for dimensions 2 through 8 for the multiplier 0xd1342543de82ef95
* are [0.958602, 0.937479, 0.870757, 0.822326, 0.820405, 0.813065, 0.760215].
*/
private static final long M = 0xd1342543de82ef95L;
/* ---------------- instance fields ---------------- */
/**
* The parameter that is used as an additive constant for the LCG.
* Must be odd.
*/
private final long a;
/**
* The per-instance state: s for the LCG; x0, x1, x2, and x3 for the XBG.
* At least one of the four fields x0, x1, x2, and x3 must be nonzero.
*/
private long s, x0, x1, x2, x3;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param a additive parameter for the LCG
* @param s initial state for the LCG
* @param x0 first word of the initial state for the XBG
* @param x1 second word of the initial state for the XBG
* @param x2 third word of the initial state for the XBG
* @param x3 fourth word of the initial state for the XBG
*/
public L64X256MixRandom(long a, long s, long x0, long x1, long x2, long x3) {
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
// If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
if ((x0 | x1 | x2 | x3) == 0) {
long v = s;
// At least three of the four values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x1 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x2 = RandomSupport.mixStafford13(v += RandomSupport.GOLDEN_RATIO_64);
this.x3 = RandomSupport.mixStafford13(v + RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link L64X256MixRandom} using the
* specified {@code long} value as the initial seed. Instances of
* {@link L64X256MixRandom} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X256MixRandom(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The seed is hashed by mixMurmur64 to produce the `a` parameter.
// The seed is hashed by mixStafford13 to produce the initial `x0`,
// which will then be used to produce the first generated value.
// The other x values are filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and mixStafford13 as the mixer.
this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
1,
RandomSupport.mixStafford13(seed),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X256MixRandom} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public L64X256MixRandom() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link L64X256MixRandom} using the specified array of
* initial seed bytes. Instances of {@link L64X256MixRandom} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public L64X256MixRandom(byte[] seed) {
// Convert the seed to 6 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4);
long a = data[0], s = data[1], x0 = data[2], x1 = data[3], x2 = data[4], x3 = data[5];
// Force a to be odd.
this.a = a | 1;
this.s = s;
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
}
/* ---------------- public methods ---------------- */
@Override
public SplittableGenerator split(SplittableGenerator source, long brine) {
// Pick a new instance "at random", but use the brine for `a`.
return new L64X256MixRandom(brine << 1, source.nextLong(),
source.nextLong(), source.nextLong(),
source.nextLong(), source.nextLong());
}
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = RandomSupport.mixLea64(s + x0);
// Update the LCG subgenerator
s = M * s + a;
// Update the XBG subgenerator
long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
{ // xoshiro256 1.0
long t = q1 << 17;
q2 ^= q0;
q3 ^= q1;
q1 ^= q2;
q0 ^= q3;
q2 ^= t;
q3 = Long.rotateLeft(q3, 45);
}
x0 = q0; x1 = q1; x2 = q2; x3 = q3;
return result;
}
}

View file

@ -0,0 +1,276 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import java.util.random.RandomGenerator.LeapableGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>128</sup>. Class {@link Xoroshiro128PlusPlus} implements
* interfaces {@link RandomGenerator} and {@link LeapableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* numbers of type {@code int}, {@code long}, {@code float}, and {@code double}
* as well as creating new {@link Xoroshiro128PlusPlus} objects
* by "jumping" or "leaping".
* <p>
* The class {@link Xoroshiro128PlusPlus} uses the {@code xoroshiro128} algorithm
* (parameters 49, 21, 28) with the "++" scrambler that computes
* {@code Long.rotateLeft(s0 + s1, 17) + s0}.
* (See David Blackman and Sebastiano Vigna, "Scrambled Linear Pseudorandom
* Number Generators," ACM Transactions on Mathematical Software, 2021.)
* Its state consists of two {@code long} fields {@code x0} and {@code x1},
* which can take on any values provided that they are not both zero.
* The period of this generator is 2<sup>128</sup>-1.
* <p>
* The 64-bit values produced by the {@code nextLong()} method are equidistributed.
* To be precise, over the course of the cycle of length 2<sup>128</sup>-1,
* each nonzero {@code long} value is generated 2<sup>64</sup> times,
* but the value 0 is generated only 2<sup>64</sup>-1 times.
* The values produced by the {@code nextInt()}, {@code nextFloat()}, and {@code nextDouble()}
* methods are likewise equidistributed.
* <p>
* Instances {@link Xoroshiro128PlusPlus} are <em>not</em> thread-safe.
* They are designed to be used so that each thread as its own instance.
* The methods {@link #jump} and {@link #leap} and {@link #jumps} and {@link #leaps}
* can be used to construct new instances of {@link Xoroshiro128PlusPlus} that traverse
* other parts of the state cycle.
* <p>
* Instances of {@link Xoroshiro128PlusPlus} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "Xoroshiro128PlusPlus",
group = "Xoroshiro",
i = 128, j = 1, k = 0,
equidistribution = 1
)
public final class Xoroshiro128PlusPlus implements LeapableGenerator {
/*
* Implementation Overview.
*
* This is an implementation of the xoroshiro128++ algorithm version 1.0,
* written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org).
*
* The jump operation moves the current generator forward by 2*64
* steps; this has the same effect as calling nextLong() 2**64
* times, but is much faster. Similarly, the leap operation moves
* the current generator forward by 2*96 steps; this has the same
* effect as calling nextLong() 2**96 times, but is much faster.
* The copy method may be used to make a copy of the current
* generator. Thus one may repeatedly and cumulatively copy and
* jump to produce a sequence of generators whose states are well
* spaced apart along the overall state cycle (indeed, the jumps()
* and leaps() methods each produce a stream of such generators).
* The generators can then be parceled out to other threads.
*
* File organization: First the non-public methods that constitute the
* main algorithm, then the public methods. Note that many methods are
* defined by classes {@link AbstractJumpableGenerator} and {@link AbstractGenerator}.
*/
/* ---------------- static fields ---------------- */
/**
* Group name.
*/
private static final String GROUP = "Xoroshiro";
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
/* ---------------- instance fields ---------------- */
/**
* The per-instance state.
* At least one of the two fields x0 and x1 must be nonzero.
*/
private long x0, x1;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param x0 first word of the initial state
* @param x1 second word of the initial state
*/
public Xoroshiro128PlusPlus(long x0, long x1) {
this.x0 = x0;
this.x1 = x1;
// If x0 and x1 are both zero, we must choose nonzero values.
if ((x0 | x1) == 0) {
this.x0 = RandomSupport.GOLDEN_RATIO_64;
this.x1 = RandomSupport.SILVER_RATIO_64;
}
}
/**
* Creates a new instance of {@link Xoroshiro128PlusPlus} using the
* specified {@code long} value as the initial seed. Instances of
* {@link Xoroshiro128PlusPlus} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public Xoroshiro128PlusPlus(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The x values are then filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
this(RandomSupport.mixStafford13(seed ^= RandomSupport.SILVER_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link Xoroshiro128PlusPlus} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public Xoroshiro128PlusPlus() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link Xoroshiro128PlusPlus} using the specified array of
* initial seed bytes. Instances of {@link Xoroshiro128PlusPlus} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public Xoroshiro128PlusPlus(byte[] seed) {
// Convert the seed to 2 long values, which are not both zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 2, 2);
long x0 = data[0], x1 = data[1];
this.x0 = x0;
this.x1 = x1;
}
/* ---------------- public methods ---------------- */
public Xoroshiro128PlusPlus copy() {
return new Xoroshiro128PlusPlus(x0, x1);
}
/*
* The following two comments are quoted from http://prng.di.unimi.it/xoroshiro128plusplus.c
*/
/*
* To the extent possible under law, the author has dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
* <p>
* See http://creativecommons.org/publicdomain/zero/1.0/.
*/
/*
* This is xoroshiro128++ 1.0, one of our all-purpose, rock-solid,
* small-state generators. It is extremely (sub-ns) fast and it passes all
* tests we are aware of, but its state space is large enough only for
* mild parallelism.
* <p>
* For generating just floating-point numbers, xoroshiro128+ is even
* faster (but it has a very mild bias, see notes in the comments).
* <p>
* The state must be seeded so that it is not everywhere zero. If you have
* a 64-bit seed, we suggest to seed a splitmix64 generator and use its
* output to fill s.
*/
@Override
public long nextLong() {
final long s0 = x0;
long s1 = x1;
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = Long.rotateLeft(s0 + s1, 17) + s0; // "plusplus" scrambler
s1 ^= s0;
x0 = Long.rotateLeft(s0, 49) ^ s1 ^ (s1 << 21); // a, b
x1 = Long.rotateLeft(s1, 28); // c
return result;
}
@Override
public double jumpDistance() {
return 0x1.0p64;
}
@Override
public double leapDistance() {
return 0x1.0p96;
}
private static final long[] JUMP_TABLE = { 0x2bd7a6a6e99c2ddcL, 0x0992ccaf6a6fca05L };
private static final long[] LEAP_TABLE = { 0x360fd5f2cf8d5d99L, 0x9c6e6877736c46e3L };
@Override
public void jump() {
jumpAlgorithm(JUMP_TABLE);
}
@Override
public void leap() {
jumpAlgorithm(LEAP_TABLE);
}
private void jumpAlgorithm(long[] table) {
long s0 = 0, s1 = 0;
for (int i = 0; i < table.length; i++) {
for (int b = 0; b < 64; b++) {
if ((table[i] & (1L << b)) != 0) {
s0 ^= x0;
s1 ^= x1;
}
nextLong();
}
}
x0 = s0;
x1 = s1;
}
}

View file

@ -0,0 +1,307 @@
/*
* Copyright (c) 2021, 2024, 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 jdk.internal.random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator;
import java.util.random.RandomGenerator.LeapableGenerator;
import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/**
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
* is roughly 2<sup>256</sup>. Class {@link Xoshiro256PlusPlus} implements
* interfaces {@link RandomGenerator} and {@link LeapableGenerator},
* and therefore supports methods for producing pseudorandomly chosen
* values of type {@code int}, {@code long}, {@code float}, {@code double},
* and {@code boolean} (and for producing streams of pseudorandomly chosen
* numbers of type {@code int}, {@code long}, and {@code double}),
* as well as methods for creating new {@link Xoshiro256PlusPlus} objects
* by moving forward either a large distance (2<sup>128</sup>) or a very large
* distance (2<sup>192</sup>) around the state cycle.
* <p>
* Series of generated values pass the TestU01 BigCrush and PractRand test suites
* that measure independence and uniformity properties of random number generators.
* (Most recently validated with
* <a href="http://simul.iro.umontreal.ca/testu01/tu01.html">version 1.2.3 of TestU01</a>
* and <a href="http://pracrand.sourceforge.net">version 0.90 of PractRand</a>.
* Note that TestU01 BigCrush was used to test not only values produced by the {@code nextLong()}
* method but also the result of bit-reversing each value produced by {@code nextLong()}.)
* These tests validate only the methods for certain
* types and ranges, but similar properties are expected to hold, at
* least approximately, for others as well.
* <p>
* The class {@link Xoshiro256PlusPlus} uses the {@code xoshiro256} algorithm,
* version 1.0 (parameters 17, 45), with the "++" scrambler that computes
* {@code Long.rotateLeft(s0 + s3, 23) + s0}.
* (See David Blackman and Sebastiano Vigna, "Scrambled Linear Pseudorandom
* Number Generators," ACM Transactions on Mathematical Software, 2021.)
* Its state consists of four {@code long} fields {@code x0}, {@code x1}, {@code x2},
* and {@code x3}, which can take on any values provided that they are not all zero.
* The period of this generator is 2<sup>256</sup>-1.
* <p>
* The 64-bit values produced by the {@code nextLong()} method are equidistributed.
* To be precise, over the course of the cycle of length 2<sup>256</sup>-1,
* each nonzero {@code long} value is generated 2<sup>192</sup> times,
* but the value 0 is generated only 2<sup>192</sup>-1 times.
* The values produced by the {@code nextInt()}, {@code nextFloat()}, and {@code nextDouble()}
* methods are likewise equidistributed.
* Moreover, the 64-bit values produced by the {@code nextLong()} method are 3-equidistributed.
* <p>
* Instances {@link Xoshiro256PlusPlus} are <em>not</em> thread-safe.
* They are designed to be used so that each thread as its own instance.
* The methods {@link #jump} and {@link #leap} and {@link #jumps} and {@link #leaps}
* can be used to construct new instances of {@link Xoshiro256PlusPlus} that traverse
* other parts of the state cycle.
* <p>
* Instances of {@link Xoshiro256PlusPlus} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 17
*
*/
@RandomGeneratorProperties(
name = "Xoshiro256PlusPlus",
group = "Xoshiro",
i = 256, j = 1, k = 0,
equidistribution = 3
)
public final class Xoshiro256PlusPlus implements LeapableGenerator {
/*
* Implementation Overview.
*
* This is an implementation of the xoshiro256++ algorithm version 1.0,
* written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org).
*
* The jump operation moves the current generator forward by 2*128
* steps; this has the same effect as calling nextLong() 2**128
* times, but is much faster. Similarly, the leap operation moves
* the current generator forward by 2*192 steps; this has the same
* effect as calling nextLong() 2**192 times, but is much faster.
* The copy method may be used to make a copy of the current
* generator. Thus one may repeatedly and cumulatively copy and
* jump to produce a sequence of generators whose states are well
* spaced apart along the overall state cycle (indeed, the jumps()
* and leaps() methods each produce a stream of such generators).
* The generators can then be parceled out to other threads.
*
* File organization: First static fields, then instance
* fields, then constructors, then instance methods.
*/
/* ---------------- static fields ---------------- */
/**
* The seed generator for default constructors.
*/
private static final AtomicLong DEFAULT_GEN = new AtomicLong(RandomSupport.initialSeed());
/* ---------------- instance fields ---------------- */
/**
* The per-instance state.
* At least one of the four fields x0, x1, x2, and x3 must be nonzero.
*/
private long x0, x1, x2, x3;
/* ---------------- constructors ---------------- */
/**
* Basic constructor that initializes all fields from parameters.
* It then adjusts the field values if necessary to ensure that
* all constraints on the values of fields are met.
*
* @param x0 first word of the initial state
* @param x1 second word of the initial state
* @param x2 third word of the initial state
* @param x3 fourth word of the initial state
*/
public Xoshiro256PlusPlus(long x0, long x1, long x2, long x3) {
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
// If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
if ((x0 | x1 | x2 | x3) == 0) {
// At least three of the four values generated here will be nonzero.
this.x0 = RandomSupport.mixStafford13(x0 += RandomSupport.GOLDEN_RATIO_64);
this.x1 = (x0 += RandomSupport.GOLDEN_RATIO_64);
this.x2 = (x0 += RandomSupport.GOLDEN_RATIO_64);
this.x3 = (x0 += RandomSupport.GOLDEN_RATIO_64);
}
}
/**
* Creates a new instance of {@link Xoshiro256PlusPlus} using the
* specified {@code long} value as the initial seed. Instances of
* {@link Xoshiro256PlusPlus} created with the same seed in the same
* program generate identical sequences of values.
*
* @param seed the initial seed
*/
public Xoshiro256PlusPlus(long seed) {
// Using a value with irregularly spaced 1-bits to xor the seed
// argument tends to improve "pedestrian" seeds such as 0 or
// other small integers. We may as well use SILVER_RATIO_64.
//
// The x values are then filled in as if by a SplitMix PRNG with
// GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
this(RandomSupport.mixStafford13(seed ^= RandomSupport.SILVER_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link Xoshiro256PlusPlus} that is likely to
* generate sequences of values that are statistically independent
* of those of any other instances in the current program execution,
* but may, and typically does, vary across program invocations.
*/
public Xoshiro256PlusPlus() {
// Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
this(DEFAULT_GEN.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
}
/**
* Creates a new instance of {@link Xoshiro256PlusPlus} using the specified array of
* initial seed bytes. Instances of {@link Xoshiro256PlusPlus} created with the same
* seed array in the same program execution generate identical sequences of values.
*
* @param seed the initial seed
*/
public Xoshiro256PlusPlus(byte[] seed) {
// Convert the seed to 4 long values, which are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 4, 4);
long x0 = data[0], x1 = data[1], x2 = data[2], x3 = data[3];
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
}
/* ---------------- public methods ---------------- */
public Xoshiro256PlusPlus copy() {
return new Xoshiro256PlusPlus(x0, x1, x2, x3);
}
/*
* The following two comments are quoted from http://prng.di.unimi.it/xoshiro256plusplus.c
*/
/*
* To the extent possible under law, the author has dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
* <p>
* See http://creativecommons.org/publicdomain/zero/1.0/.
*/
/*
* This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
* It has excellent (sub-ns) speed, a state (256 bits) that is large
* enough for any parallel application, and it passes all tests we are
* aware of.
*
* For generating just floating-point numbers, xoshiro256+ is even faster.
*
* The state must be seeded so that it is not everywhere zero. If you have
* a 64-bit seed, we suggest to seed a splitmix64 generator and use its
* output to fill s.
*/
@Override
public long nextLong() {
// Compute the result based on current state information
// (this allows the computation to be overlapped with state update).
final long result = Long.rotateLeft(x0 + x3, 23) + x0; // "plusplus" scrambler
long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
{ // xoshiro256 1.0
long t = q1 << 17;
q2 ^= q0;
q3 ^= q1;
q1 ^= q2;
q0 ^= q3;
q2 ^= t;
q3 = Long.rotateLeft(q3, 45);
}
x0 = q0; x1 = q1; x2 = q2; x3 = q3;
return result;
}
@Override
public double jumpDistance() {
return 0x1.0p128;
}
@Override
public double leapDistance() {
return 0x1.0p192;
}
private static final long[] JUMP_TABLE = {
0x180ec6d33cfd0abaL, 0xd5a61266f0c9392cL, 0xa9582618e03fc9aaL, 0x39abdc4529b1661cL };
private static final long[] LEAP_TABLE = {
0x76e15d3efefdcbbfL, 0xc5004e441c522fb3L, 0x77710069854ee241L, 0x39109bb02acbe635L };
@Override
public void jump() {
jumpAlgorithm(JUMP_TABLE);
}
@Override
public void leap() {
jumpAlgorithm(LEAP_TABLE);
}
private void jumpAlgorithm(long[] table) {
long s0 = 0, s1 = 0, s2 = 0, s3 = 0;
for (int i = 0; i < table.length; i++) {
for (int b = 0; b < 64; b++) {
if ((table[i] & (1L << b)) != 0) {
s0 ^= x0;
s1 ^= x1;
s2 ^= x2;
s3 ^= x3;
}
nextLong();
}
}
x0 = s0;
x1 = s1;
x2 = s2;
x3 = s3;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@ -268,8 +268,6 @@ module java.base {
jdk.jfr;
exports jdk.internal.util.xml.impl to
jdk.jfr;
exports jdk.internal.util.random to
jdk.random;
exports jdk.internal.util to
java.desktop,
java.prefs,
@ -396,7 +394,6 @@ module java.base {
uses java.time.chrono.AbstractChronology;
uses java.time.chrono.Chronology;
uses java.time.zone.ZoneRulesProvider;
uses java.util.random.RandomGenerator;
uses java.util.spi.CalendarDataProvider;
uses java.util.spi.CalendarNameProvider;
uses java.util.spi.CurrencyNameProvider;
@ -425,6 +422,16 @@ module java.base {
provides java.util.random.RandomGenerator with
java.security.SecureRandom,
java.util.Random,
java.util.SplittableRandom;
java.util.SplittableRandom,
jdk.internal.random.L32X64MixRandom,
jdk.internal.random.L64X128MixRandom,
jdk.internal.random.L64X128StarStarRandom,
jdk.internal.random.L64X256MixRandom,
jdk.internal.random.L64X1024MixRandom,
jdk.internal.random.L128X128MixRandom,
jdk.internal.random.L128X256MixRandom,
jdk.internal.random.L128X1024MixRandom,
jdk.internal.random.Xoroshiro128PlusPlus,
jdk.internal.random.Xoshiro256PlusPlus;
}