mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8202449: overflow handling in Random.doubles
Reviewed-by: darcy
This commit is contained in:
parent
c15e10fb6c
commit
c8cff1bd6f
5 changed files with 82 additions and 71 deletions
|
@ -256,7 +256,8 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
private static final long addend = 0xBL;
|
private static final long addend = 0xBL;
|
||||||
private static final long mask = (1L << 48) - 1;
|
private static final long mask = (1L << 48) - 1;
|
||||||
|
|
||||||
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
|
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << Double.PRECISION)
|
||||||
|
private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << Float.PRECISION)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new random number generator. This constructor sets
|
* Creates a new random number generator. This constructor sets
|
||||||
|
@ -598,12 +599,12 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
* low-order bit of the significand would be 0 than that it would be 1.]
|
* low-order bit of the significand would be 0 than that it would be 1.]
|
||||||
*
|
*
|
||||||
* @return the next pseudorandom, uniformly distributed {@code float}
|
* @return the next pseudorandom, uniformly distributed {@code float}
|
||||||
* value between {@code 0.0} and {@code 1.0} from this
|
* value between {@code 0.0f} and {@code 1.0f} from this
|
||||||
* random number generator's sequence
|
* random number generator's sequence
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float nextFloat() {
|
public float nextFloat() {
|
||||||
return next(24) / ((float)(1 << 24));
|
return next(Float.PRECISION) * FLOAT_UNIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -644,7 +645,7 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public double nextDouble() {
|
public double nextDouble() {
|
||||||
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
|
return (((long)(next(Double.PRECISION - 27)) << 27) + next(27)) * DOUBLE_UNIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double nextNextGaussian;
|
private double nextNextGaussian;
|
||||||
|
@ -1070,26 +1071,12 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
* pseudorandom {@code double} values, each conforming to the given origin
|
* pseudorandom {@code double} values, each conforming to the given origin
|
||||||
* (inclusive) and bound (exclusive).
|
* (inclusive) and bound (exclusive).
|
||||||
*
|
*
|
||||||
* <p>A pseudorandom {@code double} value is generated as if it's the result
|
|
||||||
* of calling the following method with the origin and bound:
|
|
||||||
* <pre> {@code
|
|
||||||
* double nextDouble(double origin, double bound) {
|
|
||||||
* double r = nextDouble();
|
|
||||||
* r = r * (bound - origin) + origin;
|
|
||||||
* if (r >= bound) // correct for rounding
|
|
||||||
* r = Math.nextDown(bound);
|
|
||||||
* return r;
|
|
||||||
* }}</pre>
|
|
||||||
*
|
|
||||||
* @param streamSize the number of values to generate
|
* @param streamSize the number of values to generate
|
||||||
* @param randomNumberOrigin the origin (inclusive) of each random value
|
* @param randomNumberOrigin the origin (inclusive) of each random value
|
||||||
* @param randomNumberBound the bound (exclusive) of each random value
|
* @param randomNumberBound the bound (exclusive) of each random value
|
||||||
* @return a stream of pseudorandom {@code double} values,
|
* @return a stream of pseudorandom {@code double} values,
|
||||||
* each with the given origin (inclusive) and bound (exclusive)
|
* each with the given origin (inclusive) and bound (exclusive)
|
||||||
* @throws IllegalArgumentException if {@code streamSize} is less than zero,
|
* @throws IllegalArgumentException {@inheritDoc}
|
||||||
* or {@code randomNumberOrigin} is not finite,
|
|
||||||
* or {@code randomNumberBound} is not finite, or {@code randomNumberOrigin}
|
|
||||||
* is greater than or equal to {@code randomNumberBound}
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -1101,18 +1088,7 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
* Returns an effectively unlimited stream of pseudorandom {@code
|
* Returns an effectively unlimited stream of pseudorandom {@code
|
||||||
* double} values, each conforming to the given origin (inclusive) and bound
|
* double} values, each conforming to the given origin (inclusive) and bound
|
||||||
* (exclusive).
|
* (exclusive).
|
||||||
*
|
|
||||||
* <p>A pseudorandom {@code double} value is generated as if it's the result
|
|
||||||
* of calling the following method with the origin and bound:
|
|
||||||
* <pre> {@code
|
|
||||||
* double nextDouble(double origin, double bound) {
|
|
||||||
* double r = nextDouble();
|
|
||||||
* r = r * (bound - origin) + origin;
|
|
||||||
* if (r >= bound) // correct for rounding
|
|
||||||
* r = Math.nextDown(bound);
|
|
||||||
* return r;
|
|
||||||
* }}</pre>
|
|
||||||
*
|
|
||||||
* @implNote This method is implemented to be equivalent to {@code
|
* @implNote This method is implemented to be equivalent to {@code
|
||||||
* doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
|
* doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
|
||||||
*
|
*
|
||||||
|
@ -1120,8 +1096,7 @@ public class Random implements RandomGenerator, java.io.Serializable {
|
||||||
* @param randomNumberBound the bound (exclusive) of each random value
|
* @param randomNumberBound the bound (exclusive) of each random value
|
||||||
* @return a stream of pseudorandom {@code double} values,
|
* @return a stream of pseudorandom {@code double} values,
|
||||||
* each with the given origin (inclusive) and bound (exclusive)
|
* each with the given origin (inclusive) and bound (exclusive)
|
||||||
* @throws IllegalArgumentException if {@code randomNumberOrigin}
|
* @throws IllegalArgumentException {@inheritDoc}
|
||||||
* is greater than or equal to {@code randomNumberBound}
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,7 +24,6 @@
|
||||||
*/
|
*/
|
||||||
package java.util;
|
package java.util;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.random.RandomGenerator;
|
import java.util.random.RandomGenerator;
|
||||||
import java.util.random.RandomGenerator.SplittableGenerator;
|
import java.util.random.RandomGenerator.SplittableGenerator;
|
||||||
|
@ -551,9 +550,7 @@ public final class SplittableRandom implements RandomGenerator, SplittableGenera
|
||||||
* @param randomNumberBound the bound (exclusive) of each random value
|
* @param randomNumberBound the bound (exclusive) of each random value
|
||||||
* @return a stream of pseudorandom {@code double} values,
|
* @return a stream of pseudorandom {@code double} values,
|
||||||
* each with the given origin (inclusive) and bound (exclusive)
|
* each with the given origin (inclusive) and bound (exclusive)
|
||||||
* @throws IllegalArgumentException if {@code streamSize} is
|
* @throws IllegalArgumentException {@inheritDoc}
|
||||||
* less than zero, or {@code randomNumberOrigin}
|
|
||||||
* is greater than or equal to {@code randomNumberBound}
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
|
public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
|
||||||
|
@ -572,8 +569,7 @@ public final class SplittableRandom implements RandomGenerator, SplittableGenera
|
||||||
* @param randomNumberBound the bound (exclusive) of each random value
|
* @param randomNumberBound the bound (exclusive) of each random value
|
||||||
* @return a stream of pseudorandom {@code double} values,
|
* @return a stream of pseudorandom {@code double} values,
|
||||||
* each with the given origin (inclusive) and bound (exclusive)
|
* each with the given origin (inclusive) and bound (exclusive)
|
||||||
* @throws IllegalArgumentException if {@code randomNumberOrigin}
|
* @throws IllegalArgumentException {@inheritDoc}
|
||||||
* is greater than or equal to {@code randomNumberBound}
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
|
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
|
||||||
|
|
|
@ -540,10 +540,7 @@ public interface RandomGenerator {
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code origin} is not finite,
|
* @throws IllegalArgumentException if {@code origin} is not finite,
|
||||||
* or {@code bound} is not finite, or {@code origin}
|
* or {@code bound} is not finite, or {@code origin}
|
||||||
* is greater than or equal to {@code bound}, or
|
* is greater than or equal to {@code bound}
|
||||||
* the difference between {@code bound} and {@code origin}
|
|
||||||
* is so large that it cannot be represented as a finite
|
|
||||||
* {@code float} value
|
|
||||||
*
|
*
|
||||||
* @implSpec The default implementation verifies that the {@code origin}
|
* @implSpec The default implementation verifies that the {@code origin}
|
||||||
* and {@code bound} are valid then invokes {@code nextFloat()}
|
* and {@code bound} are valid then invokes {@code nextFloat()}
|
||||||
|
@ -606,11 +603,8 @@ public interface RandomGenerator {
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code origin} is not finite,
|
* @throws IllegalArgumentException if {@code origin} is not finite,
|
||||||
* or {@code bound} is not finite, or {@code origin}
|
* or {@code bound} is not finite, or {@code origin}
|
||||||
* is greater than or equal to {@code bound}, or
|
* is greater than or equal to {@code bound}
|
||||||
* the difference between {@code bound} and {@code origin}
|
|
||||||
* is so large that it cannot be represented as a finite
|
|
||||||
* {@code double} value
|
|
||||||
*
|
|
||||||
* @implSpec The default implementation verifies that the {@code origin}
|
* @implSpec The default implementation verifies that the {@code origin}
|
||||||
* and {@code bound} are valid, then invokes {@code nextDouble()}
|
* and {@code bound} are valid, then invokes {@code nextDouble()}
|
||||||
* scaling and translating the result to fit between {@code origin}
|
* scaling and translating the result to fit between {@code origin}
|
||||||
|
|
|
@ -145,7 +145,7 @@ public class RandomSupport {
|
||||||
* @throws IllegalArgumentException if {@code bound} fails to be positive and finite
|
* @throws IllegalArgumentException if {@code bound} fails to be positive and finite
|
||||||
*/
|
*/
|
||||||
public static void checkBound(float bound) {
|
public static void checkBound(float bound) {
|
||||||
if (!(bound > 0.0 && bound < Float.POSITIVE_INFINITY)) {
|
if (!(0.0f < bound && bound < Float.POSITIVE_INFINITY)) {
|
||||||
throw new IllegalArgumentException(BAD_FLOATING_BOUND);
|
throw new IllegalArgumentException(BAD_FLOATING_BOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ public class RandomSupport {
|
||||||
* @throws IllegalArgumentException if {@code bound} fails to be positive and finite
|
* @throws IllegalArgumentException if {@code bound} fails to be positive and finite
|
||||||
*/
|
*/
|
||||||
public static void checkBound(double bound) {
|
public static void checkBound(double bound) {
|
||||||
if (!(bound > 0.0 && bound < Double.POSITIVE_INFINITY)) {
|
if (!(0.0 < bound && bound < Double.POSITIVE_INFINITY)) {
|
||||||
throw new IllegalArgumentException(BAD_FLOATING_BOUND);
|
throw new IllegalArgumentException(BAD_FLOATING_BOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,11 +195,13 @@ public class RandomSupport {
|
||||||
* @param origin the least value (inclusive) in the range
|
* @param origin the least value (inclusive) in the range
|
||||||
* @param bound the upper bound (exclusive) of the range
|
* @param bound the upper bound (exclusive) of the range
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code origin} is not finite, {@code bound} is not finite,
|
* @throws IllegalArgumentException if {@code origin} is not finite,
|
||||||
* or {@code bound - origin} is not finite
|
* or {@code bound} is not finite, or {@code origin}
|
||||||
|
* is greater than or equal to {@code bound}
|
||||||
*/
|
*/
|
||||||
public static void checkRange(float origin, float bound) {
|
public static void checkRange(float origin, float bound) {
|
||||||
if (!(origin < bound && (bound - origin) < Float.POSITIVE_INFINITY)) {
|
if (!(Float.NEGATIVE_INFINITY < origin && origin < bound &&
|
||||||
|
bound < Float.POSITIVE_INFINITY)) {
|
||||||
throw new IllegalArgumentException(BAD_RANGE);
|
throw new IllegalArgumentException(BAD_RANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,11 +212,13 @@ public class RandomSupport {
|
||||||
* @param origin the least value (inclusive) in the range
|
* @param origin the least value (inclusive) in the range
|
||||||
* @param bound the upper bound (exclusive) of the range
|
* @param bound the upper bound (exclusive) of the range
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code origin} is not finite, {@code bound} is not finite,
|
* @throws IllegalArgumentException if {@code origin} is not finite,
|
||||||
* or {@code bound - origin} is not finite
|
* or {@code bound} is not finite, or {@code origin}
|
||||||
|
* is greater than or equal to {@code bound}
|
||||||
*/
|
*/
|
||||||
public static void checkRange(double origin, double bound) {
|
public static void checkRange(double origin, double bound) {
|
||||||
if (!(origin < bound && (bound - origin) < Double.POSITIVE_INFINITY)) {
|
if (!(Double.NEGATIVE_INFINITY < origin && origin < bound &&
|
||||||
|
bound < Double.POSITIVE_INFINITY)) {
|
||||||
throw new IllegalArgumentException(BAD_RANGE);
|
throw new IllegalArgumentException(BAD_RANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,8 +347,8 @@ public class RandomSupport {
|
||||||
* This is the form of {@link RandomGenerator#nextLong() nextLong}() used by
|
* This is the form of {@link RandomGenerator#nextLong() nextLong}() used by
|
||||||
* a {@link LongStream} {@link Spliterator} and by the public method
|
* a {@link LongStream} {@link Spliterator} and by the public method
|
||||||
* {@link RandomGenerator#nextLong(long, long) nextLong}(origin, bound). If
|
* {@link RandomGenerator#nextLong(long, long) nextLong}(origin, bound). If
|
||||||
* {@code origin} is greater than {@code bound}, then this method simply
|
* {@code origin} is greater than or equal to {@code bound},
|
||||||
* calls the unbounded version of
|
* then this method simply calls the unbounded version of
|
||||||
* {@link RandomGenerator#nextLong() nextLong}(), choosing pseudorandomly
|
* {@link RandomGenerator#nextLong() nextLong}(), choosing pseudorandomly
|
||||||
* from among all 2<sup>64</sup> possible {@code long} values}, and
|
* from among all 2<sup>64</sup> possible {@code long} values}, and
|
||||||
* otherwise uses one or more calls to
|
* otherwise uses one or more calls to
|
||||||
|
@ -508,8 +512,8 @@ public class RandomSupport {
|
||||||
* This is the form of {@link RandomGenerator#nextInt() nextInt}() used by
|
* This is the form of {@link RandomGenerator#nextInt() nextInt}() used by
|
||||||
* an {@link IntStream} {@link Spliterator} and by the public method
|
* an {@link IntStream} {@link Spliterator} and by the public method
|
||||||
* {@link RandomGenerator#nextInt(int, int) nextInt}(origin, bound). If
|
* {@link RandomGenerator#nextInt(int, int) nextInt}(origin, bound). If
|
||||||
* {@code origin} is greater than {@code bound}, then this method simply
|
* {@code origin} is greater than or equal to {@code bound},
|
||||||
* calls the unbounded version of
|
* then this method simply calls the unbounded version of
|
||||||
* {@link RandomGenerator#nextInt() nextInt}(), choosing pseudorandomly
|
* {@link RandomGenerator#nextInt() nextInt}(), choosing pseudorandomly
|
||||||
* from among all 2<sup>64</sup> possible {@code int} values}, and otherwise
|
* from among all 2<sup>64</sup> possible {@code int} values}, and otherwise
|
||||||
* uses one or more calls to {@link RandomGenerator#nextInt() nextInt}() to
|
* uses one or more calls to {@link RandomGenerator#nextInt() nextInt}() to
|
||||||
|
@ -604,8 +608,8 @@ public class RandomSupport {
|
||||||
* used by a {@link DoubleStream} {@link Spliterator} and by the public
|
* used by a {@link DoubleStream} {@link Spliterator} and by the public
|
||||||
* method
|
* method
|
||||||
* {@link RandomGenerator#nextDouble(double, double) nextDouble}(origin, bound).
|
* {@link RandomGenerator#nextDouble(double, double) nextDouble}(origin, bound).
|
||||||
* If {@code origin} is greater than {@code bound}, then this method simply
|
* {@code origin} is greater than or equal to {@code bound},
|
||||||
* calls the unbounded version of
|
* then this method simply calls the unbounded version of
|
||||||
* {@link RandomGenerator#nextDouble() nextDouble}(), and otherwise scales
|
* {@link RandomGenerator#nextDouble() nextDouble}(), and otherwise scales
|
||||||
* and translates the result of a call to
|
* and translates the result of a call to
|
||||||
* {@link RandomGenerator#nextDouble() nextDouble}() so that it lies between
|
* {@link RandomGenerator#nextDouble() nextDouble}() so that it lies between
|
||||||
|
@ -643,9 +647,15 @@ public class RandomSupport {
|
||||||
public static double boundedNextDouble(RandomGenerator rng, double origin, double bound) {
|
public static double boundedNextDouble(RandomGenerator rng, double origin, double bound) {
|
||||||
double r = rng.nextDouble();
|
double r = rng.nextDouble();
|
||||||
if (origin < bound) {
|
if (origin < bound) {
|
||||||
r = r * (bound - origin) + origin;
|
if (bound - origin < Double.POSITIVE_INFINITY) {
|
||||||
|
r = r * (bound - origin) + origin;
|
||||||
|
} else {
|
||||||
|
/* avoids overflow at the cost of 3 more multiplications */
|
||||||
|
double halfOrigin = 0.5 * origin;
|
||||||
|
r = (r * (0.5 * bound - halfOrigin) + halfOrigin) * 2.0;
|
||||||
|
}
|
||||||
if (r >= bound) // may need to correct a rounding problem
|
if (r >= bound) // may need to correct a rounding problem
|
||||||
r = Math.nextAfter(bound, origin);
|
r = Math.nextDown(bound);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -686,8 +696,8 @@ public class RandomSupport {
|
||||||
* by a {@link Stream<Float>} {@link Spliterator} (if there were any) and by
|
* by a {@link Stream<Float>} {@link Spliterator} (if there were any) and by
|
||||||
* the public method
|
* the public method
|
||||||
* {@link RandomGenerator#nextFloat(float, float) nextFloat}(origin, bound).
|
* {@link RandomGenerator#nextFloat(float, float) nextFloat}(origin, bound).
|
||||||
* If {@code origin} is greater than {@code bound}, then this method simply
|
* {@code origin} is greater than or equal to {@code bound},
|
||||||
* calls the unbounded version of
|
* then this method simply calls the unbounded version of
|
||||||
* {@link RandomGenerator#nextFloat() nextFloat}(), and otherwise scales and
|
* {@link RandomGenerator#nextFloat() nextFloat}(), and otherwise scales and
|
||||||
* translates the result of a call to
|
* translates the result of a call to
|
||||||
* {@link RandomGenerator#nextFloat() nextFloat}() so that it lies between
|
* {@link RandomGenerator#nextFloat() nextFloat}() so that it lies between
|
||||||
|
@ -715,9 +725,15 @@ public class RandomSupport {
|
||||||
public static float boundedNextFloat(RandomGenerator rng, float origin, float bound) {
|
public static float boundedNextFloat(RandomGenerator rng, float origin, float bound) {
|
||||||
float r = rng.nextFloat();
|
float r = rng.nextFloat();
|
||||||
if (origin < bound) {
|
if (origin < bound) {
|
||||||
r = r * (bound - origin) + origin;
|
if (bound - origin < Float.POSITIVE_INFINITY) {
|
||||||
|
r = r * (bound - origin) + origin;
|
||||||
|
} else {
|
||||||
|
/* avoids overflow at the cost of 3 more multiplications */
|
||||||
|
float halfOrigin = 0.5f * origin;
|
||||||
|
r = (r * (0.5f * bound - halfOrigin) + halfOrigin) * 2.0f;
|
||||||
|
}
|
||||||
if (r >= bound) // may need to correct a rounding problem
|
if (r >= bound) // may need to correct a rounding problem
|
||||||
r = Float.intBitsToFloat(Float.floatToIntBits(bound) - 1);
|
r = Math.nextDown(r);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -749,7 +765,7 @@ public class RandomSupport {
|
||||||
float r = rng.nextFloat();
|
float r = rng.nextFloat();
|
||||||
r = r * bound;
|
r = r * bound;
|
||||||
if (r >= bound) // may need to correct a rounding problem
|
if (r >= bound) // may need to correct a rounding problem
|
||||||
r = Float.intBitsToFloat(Float.floatToIntBits(bound) - 1);
|
r = Math.nextDown(r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,16 +24,24 @@
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @summary Verify nextDouble stays within range
|
* @summary Verify nextDouble stays within range
|
||||||
* @bug 8280550 8280950 8281183
|
* @bug 8280550 8280950 8281183 8202449
|
||||||
|
*
|
||||||
|
* @key randomness
|
||||||
|
* @library /test/lib
|
||||||
|
* @build jdk.test.lib.RandomFactory
|
||||||
|
* @run main RandomNextDoubleBoundary
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.SplittableRandom;
|
import java.util.SplittableRandom;
|
||||||
import java.util.random.RandomGenerator;
|
import java.util.random.RandomGenerator;
|
||||||
|
import jdk.test.lib.RandomFactory;
|
||||||
|
|
||||||
public class RandomNextDoubleBoundary {
|
public class RandomNextDoubleBoundary {
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
negativeBounds();
|
negativeBounds();
|
||||||
positiveBounds();
|
positiveBounds();
|
||||||
|
nextDoubleHugeRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void negativeBounds() {
|
private static void negativeBounds() {
|
||||||
|
@ -86,9 +94,31 @@ public class RandomNextDoubleBoundary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void nextDoubleHugeRange() {
|
||||||
|
var random = RandomFactory.getRandom();
|
||||||
|
var n = 100_000;
|
||||||
|
|
||||||
|
var origin = -(3.0 / 4.0) * Double.MAX_VALUE;
|
||||||
|
var bound = (3.0 / 4.0) * Double.MAX_VALUE;
|
||||||
|
assertTrue(bound - origin == Double.POSITIVE_INFINITY);
|
||||||
|
|
||||||
|
/* all are within [origin, bound) */
|
||||||
|
assertTrue(random.doubles(n, origin, bound)
|
||||||
|
.allMatch(d -> origin <= d && d < bound));
|
||||||
|
|
||||||
|
/* some are near the origin */
|
||||||
|
assertTrue(random.doubles(n, origin, bound)
|
||||||
|
.anyMatch(d -> d < (15.0 / 16.0) * origin));
|
||||||
|
|
||||||
|
/* some are near the bound */
|
||||||
|
assertTrue(random.doubles(n, origin, bound)
|
||||||
|
.anyMatch(d -> d > (15.0 / 16.0) * bound));
|
||||||
|
}
|
||||||
|
|
||||||
public static void assertTrue(boolean condition) {
|
public static void assertTrue(boolean condition) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue