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

L32X64MixRandom#nextLong() may return an incorrect value

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Windows 11 21H2
      openjdk version "17.0.6" 2023-01-17
      OpenJDK Runtime Environment Temurin-17.0.6+10 (build 17.0.6+10)
      OpenJDK 64-Bit Server VM Temurin-17.0.6+10 (build 17.0.6+10, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      L32X64MixRandom#NextLong() is implemented like this:

      ```
      return ((long)nextInt() << 32) ^ (long)nextInt();
      ```

      I think it's meant to simply concatenate two words.
      But `(long)nextInt()` does sign extension; if the most significant bit is 1, the upper 32 bits will be inverted.
      (e.g. When `nextInt()` returns 0xfedcba98, `(long)nextInt()` will be 0xfffffffffedcba98, instead of 0xfedcba98.)

      Because of this problem, the output of random numbers is different than originally intended.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Please run the code attached to the test case.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The first line (nextInt) looks like this:
      2a162bd60afba596 b78c76a4f8b54e56 d225cfec3c126b35 743cdf79f289f5a4
      ACTUAL -
      The second line (nextLong) looks like this:
      2a162bd60afba596 4873895bf8b54e56 d225cfec3c126b35 8bc32086f289f5a4

      The upper 32 bits of the second and fourth results are inverted.

      ---------- BEGIN SOURCE ----------
      import java.util.random.*;

      class javaprng {
          public static void main(String[] args) {
              // expected
              RandomGenerator rng = RandomGeneratorFactory.of("L32X64MixRandom").create(42);
              for (int i = 0; i < 4; i++) {
                  System.out.printf("%08x%08x ", rng.nextInt(), rng.nextInt());
              }

              System.out.println();

              // actual
              rng = RandomGeneratorFactory.of("L32X64MixRandom").create(42);
              for (int i = 0; i < 4; i++) {
                  System.out.printf("%016x ", rng.nextLong());
              }
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      https://github.com/openjdk/jdk/blob/c313e1ac7b3305b1c012755de4e94728b17e2505/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java#L255

      Change this line to:
              return ((long)nextInt() << 32) ^ Integer.toUnsignedLong(nextInt());

      But I am also concerned that this change will damage the reproducibility of random numbers.

      FREQUENCY : always


            rgiulietti Raffaello Giulietti
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: