Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8287026

Changes related to overflow handling in Random.doubles

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 19
    • core-libs
    • None
    • behavioral
    • minimal
    • As the range of valid parameters is extended, some invocations that currently throw or that return wrong results will return normally with usable outcomes.
    • Java API
    • SE

      Summary

      Remove restrictions on the size of the range of the two-argument forms of RandomGenerator.nextDouble and RandomGenerator.nextFloat.

      Problem

      The current spec requires the methods j.u.r.RandomGenerator.nextDouble(double,double) and j.u.r.RandomGenerator.nextFloat(float,float) to throw when the range [origin, bound) given by the arguments is so large that its size (bound - origin) overflows. For example, if origin = -Double.MAX_VALUE and bound = Double.MAX_VALUE, the current spec requires the methods to throw.

      The proposed implementation doesn't suffer from this limitation. The example above would work as intuitively expected. It also returns the same results as the current implementation when the range size (bound - origin) does not overflow.

      The API javadoc must match the extended behavior of the proposed implementation. The same holds for the methods' spec in java.util.Random and java.util.SplittableRandom.

      The j.u.r.RandomGenerator.doubles([long,]double,double) methods depend on the above methods, which thus are adversely affected by the current behavior, as reported by the associated bug issue. The proposed implementation addresses this as well.

      In addition, the spec in j.u.Random.doubles([long,]double,double) contains code that does not reflect the proposed implementation and which should therefore be removed from the spec itself.

      Solution

      Modify the API spec.

      Specification

      --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java
      +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java
      @@ -540,10 +540,7 @@ public interface RandomGenerator {
            *
            * @throws IllegalArgumentException if {@code origin} is not finite,
            *         or {@code bound} is not finite, or {@code origin}
      -     *         is greater than or equal to {@code bound}, or
      -     *         the difference between {@code bound} and {@code origin}
      -     *         is so large that it cannot be represented as a finite
      -     *         {@code float} value
      +     *         is greater than or equal to {@code bound}
            *
            * @implSpec The default implementation verifies that the {@code origin}
            *           and {@code bound} are valid then invokes {@code nextFloat()}
      @@ -606,11 +603,8 @@ public interface RandomGenerator {
            *
            * @throws IllegalArgumentException if {@code origin} is not finite,
            *         or {@code bound} is not finite, or {@code origin}
      -     *         is greater than or equal to {@code bound}, or
      -     *         the difference between {@code bound} and {@code origin}
      -     *         is so large that it cannot be represented as a finite
      -     *         {@code double} value
      -     *
      +     *         is greater than or equal to {@code bound}
      +
            * @implSpec The default implementation verifies that the {@code origin}
            *           and {@code bound} are valid, then invokes {@code nextDouble()}
            *           scaling and translating the result to fit between {@code origin}
      
      
      
      --- a/src/java.base/share/classes/java/util/Random.java
      +++ b/src/java.base/share/classes/java/util/Random.java
      @@ -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.]
            *
            * @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
            */
           @Override
           public float nextFloat() {
           }
      
           /**
      @@ -1070,26 +1071,12 @@ public class Random implements RandomGenerator, java.io.Serializable {
            * pseudorandom {@code double} values, each conforming to the given origin
            * (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 randomNumberOrigin the origin (inclusive) of each random value
            * @param randomNumberBound the bound (exclusive) of each random value
            * @return a stream of pseudorandom {@code double} values,
            *         each with the given origin (inclusive) and bound (exclusive)
      -     * @throws IllegalArgumentException if {@code streamSize} is less than zero,
      -     *         or {@code randomNumberOrigin} is not finite,
      -     *         or {@code randomNumberBound} is not finite, or {@code randomNumberOrigin}
      -     *         is greater than or equal to {@code randomNumberBound}
      +    * @throws IllegalArgumentException {@inheritDoc}
            * @since 1.8
            */
           @Override
      @@ -1101,18 +1088,7 @@ public class Random implements RandomGenerator, java.io.Serializable {
            * Returns an effectively unlimited stream of pseudorandom {@code
            * double} values, each conforming to the given origin (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>
      -     *
      +
            * @implNote This method is implemented to be equivalent to {@code
            * 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
            * @return a stream of pseudorandom {@code double} values,
            *         each with the given origin (inclusive) and bound (exclusive)
      -     * @throws IllegalArgumentException if {@code randomNumberOrigin}
      -     *         is greater than or equal to {@code randomNumberBound}
      +     * @throws IllegalArgumentException {@inheritDoc}
            * @since 1.8
            */
           @Override
      
      
      
      --- a/src/java.base/share/classes/java/util/SplittableRandom.java
      +++ b/src/java.base/share/classes/java/util/SplittableRandom.java
      @@ -551,9 +551,7 @@ public final class SplittableRandom implements RandomGenerator, SplittableGenera
            * @param randomNumberBound the bound (exclusive) of each random value
            * @return a stream of pseudorandom {@code double} values,
            *         each with the given origin (inclusive) and bound (exclusive)
      -     * @throws IllegalArgumentException if {@code streamSize} is
      -     *         less than zero, or {@code randomNumberOrigin}
      -     *         is greater than or equal to {@code randomNumberBound}
      +     * @throws IllegalArgumentException {@inheritDoc}
            */
           @Override
           public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
      @@ -572,8 +570,7 @@ public final class SplittableRandom implements RandomGenerator, SplittableGenera
            * @param randomNumberBound the bound (exclusive) of each random value
            * @return a stream of pseudorandom {@code double} values,
            *         each with the given origin (inclusive) and bound (exclusive)
      -     * @throws IllegalArgumentException if {@code randomNumberOrigin}
      -     *         is greater than or equal to {@code randomNumberBound}
      +     * @throws IllegalArgumentException {@inheritDoc}
            */
           @Override
           public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {

            rgiulietti Raffaello Giulietti
            cushon Liam Miller-Cushon
            Guy Steele (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: