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

SplittableRandom#nextDouble(double,double) can return result >= bound

    XMLWordPrintable

Details

    • b08
    • generic
    • generic
    • Verified

    Backports

      Description

        ADDITIONAL SYSTEM INFORMATION :
        Java 11.0.13

        A DESCRIPTION OF THE PROBLEM :
        The nextDouble​(double origin, double bound) method of java.util.SplittableRandom can return a result which is >= bound. According to the documentation (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/SplittableRandom.html#nextDouble(double,double)), the result is < bound.

        I believe the reason for this behavior is this line in the source: https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/java/util/SplittableRandom.java#L353

        r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);

        This line probably wants to create a double less than bound by decrementing the result of Double.doubleToLongBits(bound). However, when bound is negative, decrementing the long will actually make the double bigger (due to 2's complement representation). The fix is possibly as simple as "+1" instead of "-1" when bound is negative.

        I've tested this on Java 11, but looking at the source, newer versions are probably also affected: https://github.com/openjdk/jdk/blob/jdk-19+6/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java#L648

        ThreadLocalRandom also seems to be affected.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Compile and run the example code below.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Expected output:

        [some double which is between d1 (inclusive) and d2 (exclusive)]
        true
        true
        ACTUAL -
        Actual output:

        -0.9999999999999999
        true
        false

        ---------- BEGIN SOURCE ----------
        package com.example;

        import java.util.SplittableRandom;

        final class Example {

          public static void main(String[] args) {
            double d1 = -1.0000000000000002;
            double d2 = -1.0;
            var sr = new SplittableRandom(42L);
            var r = sr.nextDouble(d1, d2);
            System.out.println(r);
            System.out.println(r >= d1);
            System.out.println(r < d2);
          }
        }

        ---------- END SOURCE ----------

        FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

                darcy Joe Darcy
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                9 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: