javaopenjdk-17

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


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 }

Solution

  • 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