Default algo for RandomGenerator (L32X64MixRandom) generates the same number each time

803 Views Asked by At

The default algo for RandomGenerator ie. L32X64MixRandom as of JDK 18 (available since 17), generates the same number each time on individual invocations.

jshell> java.util.random.RandomGenerator.getDefault().nextInt(100,999)
$10 ==> 526

jshell> java.util.random.RandomGenerator.getDefault().nextInt(100,999)
$11 ==> 526

jshell> java.util.random.RandomGenerator.of("L32X64MixRandom").nextInt(100, 999)
$14 ==> 526

jshell> java.util.random.RandomGenerator.of("L32X64MixRandom").nextInt(100, 999)
$15 ==> 526

neither does javadoc sound any special caution:

Returns a pseudorandomly chosen int value between the specified origin (inclusive) and the specified bound (exclusive).

Implementation Requirements: The default implementation checks that origin and bound are positive ints. Then invokes nextInt(), limiting the result to be greater that or equal origin and less than bound. If bound is a power of two then limiting is a simple masking operation. Otherwise, the result is re-calculated by invoking nextInt() until the result is greater than or equal origin and less than bound.

While other algos including legacy ones seem to have percieveable levels of randomness eg.

jshell> java.util.random.RandomGenerator.of("Random").nextInt(100,999)
$7 ==> 451

jshell> java.util.random.RandomGenerator.of("Random").nextInt(100,999)
$8 ==> 633

jshell> java.util.random.RandomGenerator.of("L64X128MixRandom").nextInt(100, 999)
$12 ==> 570

jshell> java.util.random.RandomGenerator.of("L64X128MixRandom").nextInt(100, 999)
$13 ==> 844

Is there a reason for this level of determinism with the default choice?

EDIT: behaviour wrt. streams is pretty similar, the initial value always seem to be the same

jshell> java.util.random.RandomGenerator.getDefault().ints(100,999).limit(5).toArray()
$22 ==> int[5] { 526, 860, 258, 558, 820 }

jshell> java.util.random.RandomGenerator.getDefault().ints(100,999).limit(5).toArray()
$23 ==> int[5] { 526, 866, 448, 654, 684 }
1

There are 1 best solutions below

0
On BEST ANSWER

This is a bug listed at https://bugs.openjdk.java.net/browse/JDK-8282551

It is shown as fixed in Java 19, and there's a backport request to Java 17 and 18 (https://bugs.openjdk.java.net/browse/JDK-8284185 resolved 4/1/2022), but it's not clear when the backported fix will appear.

While this is a link-only answer, I believe it is appropriate because others will be encountering this bug and searching here.

For completeness, here's the code I used for my own test:

private static String[] algs = 
    {"L128X1024MixRandom",
    "L128X128MixRandom",
    "L128X256MixRandom",
    "L32X64MixRandom",
    "L64X1024MixRandom",
    "L64X128MixRandom",
    "L64X128StarStarRandom",
    "L64X256MixRandom",
    "Random",
    "Xoroshiro128PlusPlus",
    "Xoshiro256PlusPlus"};

public static void main(String[] args) throws Exception {
    for (String alg : algs)
    {
        System.out.println("\nAlgorithm " + alg);
        for (int i=0; i<5; i++)
        {
            RandomGenerator g = RandomGenerator.of(alg);
            System.out.println(
                    g.ints(4,0,1000)
                     .boxed()
                     .map(x -> String.format("%5d",x))
                     .collect(Collectors.joining(" ")));
        }
    }
}

And the output from one run:

Algorithm L128X1024MixRandom
  280   759    35    18
  824   668   554   754
  822   823   680   252
  629   718     3   392
   83   698   609   790

Algorithm L128X128MixRandom
  973   765   392   815
  495   164   744   418
  621   117   836   271
  787   819   463   825
  150   473   159   777

Algorithm L128X256MixRandom
   44    74   276   107
  703   802    41   743
  993   369   801   926
  456   754   138   870
  121   979   384    51

Algorithm L32X64MixRandom
  152   372   238    19
  152   334   300   942
  152   739   206   818
  152   284   200   628
  152   835   259   588

Algorithm L64X1024MixRandom
  782   247   982   974
  316   507   860   386
  571   563   166   646
  888   553   779   342
  121   750   764    68

Algorithm L64X128MixRandom
  706   202   985   510
  761   218   252   409
  992   844   765   861
  236   240   124   945
  680   983   444   689

Algorithm L64X128StarStarRandom
  619    40   879   489
  599   622   396   225
   76   359   104    31
  205   687   741   488
  141   732   509   172

Algorithm L64X256MixRandom
  929   338   648   606
  786   338   409   815
  750   363   713   722
  989   307    18   797
  154   266    20   552

Algorithm Random
  903   452   417    18
  838   888   609    32
  365   378   673   351
  758   413   665   566
  996   132   555   413

Algorithm Xoroshiro128PlusPlus
  145   864   592    22
  230    74    24   471
  596   302   294   734
  108   773   171   950
  716   694    87   726

Algorithm Xoshiro256PlusPlus
  563   528   572   853
  619   722   534    10
   87   306   594   525
  149   430   243   836
  578   938   802   539