diff --git a/CHANGELOG.md b/CHANGELOG.md index 5adcac058e3..ce808f2be5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add support for Spring Boot 4 and Spring 7 ([#4601](https://github.com/getsentry/sentry-java/pull/4601)) - NOTE: Our `sentry-opentelemetry-agentless-spring` is not working yet for Spring Boot 4. Please use `sentry-opentelemetry-agent` until OpenTelemetry has support for Spring Boot 4. - Replace `UUIDGenerator` implementation with Apache licensed code ([#4662](https://github.com/getsentry/sentry-java/pull/4662)) +- Replace `Random` implementation with MIT licensed code ([#4664](https://github.com/getsentry/sentry-java/pull/4664)) ## 8.20.0 diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 85fdd34a503..371d3b43e36 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -6986,15 +6986,22 @@ public final class io/sentry/util/PropagationTargetsUtils { public final class io/sentry/util/Random : java/io/Serializable { public fun ()V - public fun (J)V + public fun (JJ)V public fun nextBoolean ()Z + public fun nextBoolean (D)Z + public fun nextByte ()B public fun nextBytes ([B)V + public fun nextChar ()C public fun nextDouble ()D + public fun nextDouble (ZZ)D public fun nextFloat ()F + public fun nextFloat (ZZ)F public fun nextInt ()I public fun nextInt (I)I public fun nextLong ()J - public fun setSeed (J)V + public fun nextLong (J)J + public fun nextShort ()S + public fun setSeed (JJ)V } public final class io/sentry/util/SampleRateUtils { diff --git a/sentry/src/main/java/io/sentry/util/Random.java b/sentry/src/main/java/io/sentry/util/Random.java index cbd81824df1..aec6063dcb2 100644 --- a/sentry/src/main/java/io/sentry/util/Random.java +++ b/sentry/src/main/java/io/sentry/util/Random.java @@ -1,253 +1,144 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * Adapted from: https://github.com/KilianB/pcg-java/blob/master/src/main/java/com/github/kilianB/pcg/fast/PcgRSFast.java * - * 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. + * MIT License * - * 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). + * Copyright (c) 2018 * - * 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. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - package io.sentry.util; import java.util.concurrent.atomic.AtomicLong; import org.jetbrains.annotations.ApiStatus; /** - * A simplified version of {@link java.util.Random} that we use for sampling, which is much faster - * than {@link java.security.SecureRandom}. This is necessary so that some security tools do not - * flag our Random usage as potentially insecure. + * A simplified replacement for {@link java.util.Random}, based on pcg-java that we use for + * sampling, which is much faster than {@link java.security.SecureRandom}. This is necessary so that + * some security tools do not flag our Random usage as potentially insecure. */ @ApiStatus.Internal +@SuppressWarnings({"unused", "UnnecessaryParentheses", "OperatorPrecedence"}) public final class Random implements java.io.Serializable { - /** use serialVersionUID from JDK 1.1 for interoperability */ - private static final long serialVersionUID = 3905348978240129619L; - /** - * The internal state associated with this pseudorandom number generator. (The specs for the - * methods in this class describe the ongoing computation of this value.) - */ - private final AtomicLong seed; + private static final long serialVersionUID = -4257915988930727506L; + + static final AtomicLong UNIQUE_SEED = new AtomicLong(System.nanoTime()); - private static final long multiplier = 0x5DEECE66DL; - private static final long addend = 0xBL; - private static final long mask = (1L << 48) - 1; + /** Linear congruential constant. Same as MMIX by Donald Knuth and Newlib, Musl */ + private static final long MULT_64 = 6364136223846793005L; - private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) + // static final variables are inlined by default + private static final double DOUBLE_MASK = 1L << 53; + private static final float FLOAT_UNIT = (float) (1 << 24); + private static final long INTEGER_MASK = 0xFFFFFFFFL; - // IllegalArgumentException messages - static final String BadBound = "bound must be positive"; + // 64 version + /** 64 bit internal state */ + private long state; + + /** Stream number of the rng. */ + private long inc; + + private boolean gausAvailable; + private double nextGaus; + + // private static final int INTEGER_MASK_SIGNED = 0xFFFFFFFF; /** - * Creates a new random number generator. This constructor sets the seed of the random number - * generator to a value very likely to be distinct from any other invocation of this constructor. + * Create a PcgRSFast instance seeded with with 2 longs generated by xorshift*. The values chosen + * are very likely not used as seeds in any other non argument constructor of any of the classes + * provided in this library. */ public Random() { - this(seedUniquifier() ^ System.nanoTime()); + this(getRandomSeed(), getRandomSeed()); } - private static long seedUniquifier() { - // L'Ecuyer, "Tables of Linear Congruential Generators of - // Different Sizes and Good Lattice Structure", 1999 - for (; ; ) { - long current = seedUniquifier.get(); - long next = current * 1181783497276652981L; - if (seedUniquifier.compareAndSet(current, next)) return next; - } - } - - private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L); - /** - * Creates a new random number generator using a single {@code long} seed. The seed is the initial - * value of the internal state of the pseudorandom number generator which is maintained by method - * {@link #next}. + * Create a random number generator with the given seed and stream number. The seed defines the + * current state in which the rng is in and corresponds to seeds usually found in other RNG + * instances. RNGs with different seeds are able to catch up after they exhaust their period and + * produce the same numbers. (2^63). * - *

The invocation {@code new Random(seed)} is equivalent to: + *

Different stream numbers alter the increment of the rng and ensure distinct state sequences * - *

{@code
-   * Random rnd = new Random();
-   * rnd.setSeed(seed);
-   * }
+ *

Only generators with the same seed AND stream numbers will produce identical values * - * @param seed the initial seed - * @see #setSeed(long) + *

+ * + * @param seed used to compute the starting state of the RNG + * @param streamNumber used to compute the increment for the lcg. */ - public Random(long seed) { - if (getClass() == Random.class) this.seed = new AtomicLong(initialScramble(seed)); - else { - // subclass might have overriden setSeed - this.seed = new AtomicLong(); - setSeed(seed); - } + public Random(long seed, long streamNumber) { + setSeed(seed, streamNumber); } - private static long initialScramble(long seed) { - return (seed ^ multiplier) & mask; + private Random(long initialState, long increment, boolean dummy) { + setState(initialState); + setInc(increment); } /** - * Sets the seed of this random number generator using a single {@code long} seed. The general - * contract of {@code setSeed} is that it alters the state of this random number generator object - * so as to be in exactly the same state as if it had just been created with the argument {@code - * seed} as a seed. The method {@code setSeed} is implemented by class {@code Random} by - * atomically updating the seed to + * Sets the seed of this random number generator using . The general contract of setSeed is that + * it alters the state of this random number generator object so as to be in exactly the same + * state as if it had just been created with the argument seed as a seed. * - *

{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}
+ *

Only generators with the same seed AND stream numbers will produce identical values * - *

The implementation of {@code setSeed} by class {@code Random} happens to use only 48 bits of - * the given seed. In general, however, an overriding method may use all 64 bits of the {@code - * long} argument as a seed value. + *

* - * @param seed the initial seed + * @param seed used to compute the starting state of the RNG + * @param streamNumber used to compute the increment for the lcg. */ - public synchronized void setSeed(long seed) { - this.seed.set(initialScramble(seed)); - } + public void setSeed(long seed, long streamNumber) { + // TODO synchronize? + state = 0; + inc = (streamNumber << 1) | 1; // 2* + 1 + state = (state * MULT_64) + inc; + state += seed; + // Due to access to inlined vars the fast implementation is one step ahead of + // the ordinary rngs. To get same results we can skip the state update - /** - * Generates the next pseudorandom number. Subclasses should override this, as this is used by all - * other methods. - * - *

The general contract of {@code next} is that it returns an {@code int} value and if the - * argument {@code bits} is between {@code 1} and {@code 32} (inclusive), then that many low-order - * bits of the returned value will be (approximately) independently chosen bit values, each of - * which is (approximately) equally likely to be {@code 0} or {@code 1}. The method {@code next} - * is implemented by class {@code Random} by atomically updating the seed to - * - *

{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}
- * - * and returning - * - *
{@code (int)(seed >>> (48 - bits))}.
- * - * This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and - * described by Donald E. Knuth in The Art of Computer Programming, Volume 2: - * Seminumerical Algorithms, section 3.2.1. - * - * @param bits random bits - * @return the next pseudorandom value from this random number generator's sequence - * @since 1.1 - */ - private int next(int bits) { - long oldseed, nextseed; - AtomicLong seed = this.seed; - do { - oldseed = seed.get(); - nextseed = (oldseed * multiplier + addend) & mask; - } while (!seed.compareAndSet(oldseed, nextseed)); - return (int) (nextseed >>> (48 - bits)); + // state = (state * MULT_64) + inc; } - /** - * Generates random bytes and places them into a user-supplied byte array. The number of random - * bytes produced is equal to the length of the byte array. - * - *

The method {@code nextBytes} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public void nextBytes(byte[] bytes) {
-   *   for (int i = 0; i < bytes.length; )
-   *     for (int rnd = nextInt(), n = Math.min(bytes.length - i, 4);
-   *          n-- > 0; rnd >>= 8)
-   *       bytes[i++] = (byte)rnd;
-   * }
-   * }
- * - * @param bytes the byte array to fill with random bytes - * @throws NullPointerException if the byte array is null - * @since 1.1 - */ - public void nextBytes(byte[] bytes) { - for (int i = 0, len = bytes.length; i < len; ) - for (int rnd = nextInt(), n = Math.min(len - i, Integer.SIZE / Byte.SIZE); - n-- > 0; - rnd >>= Byte.SIZE) bytes[i++] = (byte) rnd; + public byte nextByte() { + state = (state * MULT_64) + inc; + return (byte) ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 24); } - /** - * The form of nextLong used by LongStream Spliterators. If origin is greater than bound, acts as - * unbounded form of nextLong, else as bounded form. - * - * @param origin the least value, unless greater than bound - * @param bound the upper bound (exclusive), must not equal origin - * @return a pseudorandom value - */ - final long internalNextLong(long origin, long bound) { - long r = nextLong(); - if (origin < bound) { - long n = bound - origin, m = n - 1; - if ((n & m) == 0L) // power of two - r = (r & m) + origin; - else if (n > 0L) { // reject over-represented candidates - for (long u = r >>> 1; // ensure nonnegative - u + m - (r = u % n) < 0L; // rejection check - u = nextLong() >>> 1) // retry - ; - r += origin; - } else { // range not representable as long - while (r < origin || r >= bound) r = nextLong(); - } + public void nextBytes(byte[] b) { + for (int i = 0; i < b.length; i++) { + state = (state * MULT_64) + inc; + b[i] = (byte) ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 24); } - return r; } - /** - * The form of nextInt used by IntStream Spliterators. For the unbounded case: uses nextInt(). For - * the bounded case with representable range: uses nextInt(int bound) For the bounded case with - * unrepresentable range: uses nextInt() - * - * @param origin the least value, unless greater than bound - * @param bound the upper bound (exclusive), must not equal origin - * @return a pseudorandom value - */ - final int internalNextInt(int origin, int bound) { - if (origin < bound) { - int n = bound - origin; - if (n > 0) { - return nextInt(n) + origin; - } else { // range not representable as int - int r; - do { - r = nextInt(); - } while (r < origin || r >= bound); - return r; - } - } else { - return nextInt(); - } + public char nextChar() { + state = (state * MULT_64) + inc; + // Why should we cast it to an int first can't we mask it to a char directly? + return (char) ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 16); } - /** - * The form of nextDouble used by DoubleStream Spliterators. - * - * @param origin the least value, unless greater than bound - * @param bound the upper bound (exclusive), must not equal origin - * @return a pseudorandom value - */ - final double internalNextDouble(double origin, double bound) { - double r = nextDouble(); - if (origin < bound) { - r = r * (bound - origin) + origin; - if (r >= bound) // correct for rounding - r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); - } - return r; + public short nextShort() { + state = (state * MULT_64) + inc; + return (short) ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 16); } /** @@ -256,108 +147,40 @@ final double internalNextDouble(double origin, double bound) { * pseudorandomly generated and returned. All 232 possible {@code int} values are * produced with (approximately) equal probability. * - *

The method {@code nextInt} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public int nextInt() {
-   *   return next(32);
-   * }
-   * }
- * * @return the next pseudorandom, uniformly distributed {@code int} value from this random number * generator's sequence */ public int nextInt() { - return next(32); + // we miss a single state and keep an old value around. but this does not alter + // The produced number but shifts them 1 back. + state = (state * MULT_64) + inc; + // long oldState = state; + return (int) (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)); } /** * Returns a pseudorandom, uniformly distributed {@code int} value between 0 (inclusive) and the - * specified value (exclusive), drawn from this random number generator's sequence. The general - * contract of {@code nextInt} is that one {@code int} value in the specified range is - * pseudorandomly generated and returned. All {@code bound} possible {@code int} values are - * produced with (approximately) equal probability. The method {@code nextInt(int bound)} is - * implemented by class {@code Random} as if by: - * - *
{@code
-   * public int nextInt(int bound) {
-   *   if (bound <= 0)
-   *     throw new IllegalArgumentException("bound must be positive");
+   * specified value (exclusive), drawn from this random number generator's sequence.
    *
-   *   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
-   *     return (int)((bound * (long)next(31)) >> 31);
-   *
-   *   int bits, val;
-   *   do {
-   *       bits = next(31);
-   *       val = bits % bound;
-   *   } while (bits - val + (bound-1) < 0);
-   *   return val;
-   * }
-   * }
- * - *

The hedge "approximately" is used in the foregoing description only because the next method - * is only approximately an unbiased source of independently chosen bits. If it were a perfect - * source of randomly chosen bits, then the algorithm shown would choose {@code int} values from - * the stated range with perfect uniformity. - * - *

The algorithm is slightly tricky. It rejects values that would result in an uneven - * distribution (due to the fact that 2^31 is not divisible by n). The probability of a value - * being rejected depends on n. The worst case is n=2^30+1, for which the probability of a reject - * is 1/2, and the expected number of iterations before the loop terminates is 2. - * - *

The algorithm treats the case where n is a power of two specially: it returns the correct - * number of high-order bits from the underlying pseudo-random number generator. In the absence of - * special treatment, the correct number of low-order bits would be returned. Linear - * congruential pseudo-random number generators such as the one implemented by this class are - * known to have short periods in the sequence of values of their low-order bits. Thus, this - * special case greatly increases the length of the sequence of values returned by successive - * calls to this method if n is a small power of two. - * - * @param bound the upper bound (exclusive). Must be positive. + * @param n the upper bound (exclusive). Must be positive. * @return the next pseudorandom, uniformly distributed {@code int} value between zero (inclusive) * and {@code bound} (exclusive) from this random number generator's sequence - * @throws IllegalArgumentException if bound is not positive - * @since 1.2 */ - public int nextInt(int bound) { - if (bound <= 0) throw new IllegalArgumentException(BadBound); - - int r = next(31); - int m = bound - 1; - if ((bound & m) == 0) // i.e., bound is a power of 2 - r = (int) ((bound * (long) r) >> 31); + public int nextInt(int n) { + state = (state * MULT_64) + inc; + int r = (int) (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 1; // Unsigned! + int m = n - 1; + if ((n & m) == 0) // i.e., bound is a power of 2 + r = (int) ((n * (long) r) >> 31); else { - for (int u = r; u - (r = u % bound) + m < 0; u = next(31)) - ; + for (int u = r; u - (r = u % n) + m < 0; ) { + state = (state * MULT_64) + inc; + u = (int) (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) >>> 1; + } } return r; } - - /** - * Returns the next pseudorandom, uniformly distributed {@code long} value from this random number - * generator's sequence. The general contract of {@code nextLong} is that one {@code long} value - * is pseudorandomly generated and returned. - * - *

The method {@code nextLong} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public long nextLong() {
-   *   return ((long)next(32) << 32) + next(32);
-   * }
-   * }
- * - * Because class {@code Random} uses a seed with only 48 bits, this algorithm will not return all - * possible {@code long} values. - * - * @return the next pseudorandom, uniformly distributed {@code long} value from this random number - * generator's sequence - */ - @SuppressWarnings("UnnecessaryParentheses") - public long nextLong() { - // it's okay that the bottom word remains signed. - return ((long) (next(32)) << 32) + next(32); - } + ; /** * Returns the next pseudorandom, uniformly distributed {@code boolean} value from this random @@ -365,102 +188,158 @@ public long nextLong() { * boolean} value is pseudorandomly generated and returned. The values {@code true} and {@code * false} are produced with (approximately) equal probability. * - *

The method {@code nextBoolean} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public boolean nextBoolean() {
-   *   return next(1) != 0;
-   * }
-   * }
- * * @return the next pseudorandom, uniformly distributed {@code boolean} value from this random * number generator's sequence - * @since 1.2 */ + @SuppressWarnings("OperatorPrecedence") public boolean nextBoolean() { - return next(1) != 0; + // Two choices either take the low bit or get a range 2 int and make an if + state = (state * MULT_64) + inc; + return (((((state >>> 22) ^ state) >>> (state >>> 61) + 22) & INTEGER_MASK) >>> 31) != 0; } - /** - * Returns the next pseudorandom, uniformly distributed {@code float} value between {@code 0.0} - * and {@code 1.0} from this random number generator's sequence. - * - *

The general contract of {@code nextFloat} is that one {@code float} value, chosen - * (approximately) uniformly from the range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), - * is pseudorandomly generated and returned. All 224 possible {@code float} values of - * the form m x 2-24, where m is a positive integer less than - * 224, are produced with (approximately) equal probability. - * - *

The method {@code nextFloat} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public float nextFloat() {
-   *   return next(24) / ((float)(1 << 24));
-   * }
-   * }
- * - *

The hedge "approximately" is used in the foregoing description only because the next method - * is only approximately an unbiased source of independently chosen bits. If it were a perfect - * source of randomly chosen bits, then the algorithm shown would choose {@code float} values from - * the stated range with perfect uniformity. - * - *

[In early versions of Java, the result was incorrectly calculated as: - * - *

{@code
-   * return next(30) / ((float)(1 << 30));
-   * }
- * - * This might seem to be equivalent, if not better, but in fact it introduced a slight - * nonuniformity because of the bias in the rounding of floating-point numbers: it was slightly - * more likely that the low-order bit of the significand would be 0 than that it would be 1.] - * - * @return the next pseudorandom, uniformly distributed {@code float} value between {@code 0.0} - * and {@code 1.0} from this random number generator's sequence - */ - public float nextFloat() { - return next(24) / ((float) (1 << 24)); + @SuppressWarnings("UnnecessaryParentheses") + public boolean nextBoolean(double probability) { + if (probability < 0.0 || probability > 1.0) + throw new IllegalArgumentException("probability must be between 0.0 and 1.0 inclusive."); + + // Borrowed from https://cs.gmu.edu/~sean/research/mersenne/MersenneTwister.java + if (probability == 0.0) return false; + if (probability == 1.0) return true; + + state = (state * MULT_64) + inc; + long l = ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22))) & INTEGER_MASK; + + state = (state * MULT_64) + inc; + + return (((l >>> 6) << 27) + + (((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) & INTEGER_MASK) >>> 5)) + / DOUBLE_MASK + < probability; + } + + public long nextLong() { + + state = (state * MULT_64) + inc; + // No need to mask if we shift by 32 bits + long l = (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)); + + state = (state * MULT_64) + inc; + long j = (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)); + + // Long keep consistent with the random definition of keeping the lower word + // signed, + // But should this really be the case? Why don't we mask the sign bit? + return (l << 32) + (int) j; + } + + public long nextLong(long n) { + if (n == 0) throw new IllegalArgumentException("n has to be greater than 0"); + + long bits; + long val; + do { + state = (state * MULT_64) + inc; + // No need to mask if we shift by 32 bits + long l = (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)); + + state = (state * MULT_64) + inc; + long j = (((state >>> 22) ^ state) >>> ((state >>> 61) + 22)); + + bits = ((l << 32) + (int) j >>> 1); + val = bits % n; + } while (bits - val + (n - 1) < 0); + return val; } - /** - * Returns the next pseudorandom, uniformly distributed {@code double} value between {@code 0.0} - * and {@code 1.0} from this random number generator's sequence. - * - *

The general contract of {@code nextDouble} is that one {@code double} value, chosen - * (approximately) uniformly from the range {@code 0.0d} (inclusive) to {@code 1.0d} (exclusive), - * is pseudorandomly generated and returned. - * - *

The method {@code nextDouble} is implemented by class {@code Random} as if by: - * - *

{@code
-   * public double nextDouble() {
-   *   return (((long)next(26) << 27) + next(27))
-   *     / (double)(1L << 53);
-   * }
-   * }
- * - *

The hedge "approximately" is used in the foregoing description only because the {@code next} - * method is only approximately an unbiased source of independently chosen bits. If it were a - * perfect source of randomly chosen bits, then the algorithm shown would choose {@code double} - * values from the stated range with perfect uniformity. - * - *

[In early versions of Java, the result was incorrectly calculated as: - * - *

{@code
-   * return (((long)next(27) << 27) + next(27))
-   *   / (double)(1L << 54);
-   * }
- * - * This might seem to be equivalent, if not better, but in fact it introduced a large - * nonuniformity because of the bias in the rounding of floating-point numbers: it was three times - * as likely that the low-order bit of the significand would be 0 than that it would be 1! This - * nonuniformity probably doesn't matter much in practice, but we strive for perfection.] - * - * @return the next pseudorandom, uniformly distributed {@code double} value between {@code 0.0} - * and {@code 1.0} from this random number generator's sequence - * @see Math#random - */ - @SuppressWarnings("UnnecessaryParentheses") public double nextDouble() { - return (((long) (next(26)) << 27) + next(27)) * DOUBLE_UNIT; + state = (state * MULT_64) + inc; + long l = ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22))) & INTEGER_MASK; + state = (state * MULT_64) + inc; + return (((l >>> 6) << 27) + + (((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) & INTEGER_MASK) >>> 5)) + / DOUBLE_MASK; + } + + public double nextDouble(boolean includeZero, boolean includeOne) { + double d = 0.0; + do { + state = (state * MULT_64) + inc; + long l = ((((state >>> 22) ^ state) >>> ((state >>> 61) + 22))) & INTEGER_MASK; + state = (state * MULT_64) + inc; + d = + (((l >>> 6) << 27) + + (((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) & INTEGER_MASK) >>> 5)) + / DOUBLE_MASK; + + // grab a value, initially from half-open [0.0, 1.0) + if (includeOne) { + // Only generate the boolean if it really is the case or we scramble the state + state = (state * MULT_64) + inc; + if ((((((state >>> 22) ^ state) >>> (state >>> 61) + 22) & INTEGER_MASK) >>> 31) != 0) { + d += 1.0; + } + } + + } while ((d > 1.0) + || // everything above 1.0 is always invalid + (!includeZero && d == 0.0)); // if we're not including zero, 0.0 is invalid + return d; + } + + public float nextFloat() { + state = (state * MULT_64) + inc; + return (((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) & INTEGER_MASK) >>> 8) + / FLOAT_UNIT; + } + + public float nextFloat(boolean includeZero, boolean includeOne) { + float d = 0.0f; + do { + state = (state * MULT_64) + inc; + d = + (((((state >>> 22) ^ state) >>> ((state >>> 61) + 22)) & INTEGER_MASK) >>> 8) + / FLOAT_UNIT; // grab a + // value, + // initially + // from + // half-open + // [0.0f, + // 1.0f) + if (includeOne) { + // Only generate the boolean if it really is the case or we scramble the state + state = (state * MULT_64) + inc; + if ((((((state >>> 22) ^ state) >>> (state >>> 61) + 22) & INTEGER_MASK) >>> 31) != 0) { + d += 1.0f; + } + } + } while ((d > 1.0f) + || // everything above 1.0f is always invalid + (!includeZero && d == 0.0f)); // if we're not including zero, 0.0f is invalid + return d; + } + + private void setInc(long increment) { + if (increment == 0 || increment % 2 == 0) { + throw new IllegalArgumentException("Increment may not be 0 or even. Value: " + increment); + } + this.inc = increment; + } + + private void setState(long state) { + this.state = state; + } + + private static long getRandomSeed() { + // xorshift64* + for (; ; ) { + long current = UNIQUE_SEED.get(); + long next = current; + next ^= next >> 12; + next ^= next << 25; // b + next ^= next >> 27; // c + next *= 0x2545F4914F6CDD1DL; + if (UNIQUE_SEED.compareAndSet(current, next)) return next; + } } }