View Javadoc
1   /*
2    * License : The MIT License
3    * Copyright(c) 2022 Olyutorskii
4    */
5   
6   package io.github.olyutorskii.aletojio.rng.mwc;
7   
8   /**
9    * Complementary-multiply-with-carry random number generator.
10   *
11   * <p>Random sequence X(n) is derived as follows with parameter a(multiplier), b(divisor).
12   * <ul>
13   * <li>{@code T(n) = a * X(n-r) + C(n-1)}
14   * <li>{@code C(n) = T(n) / b}
15   * <li>{@code Y(n) = T(n) mod b}
16   * <li>{@code X(n) = b - 1 - Y(n)}
17   * </ul>
18   *
19   * <p>r is the length of the record that stores past results.
20   * "carry" comes from C(n-1).
21   *
22   * @see <a href="https://en.wikipedia.org/wiki/Multiply-with-carry_pseudorandom_number_generator">
23   * Multiply-with-carry pseudorandom number generator (Wikipedia)
24   * </a>
25   */
26  public class Cmwc extends Mwc {
27  
28      private static final int  DEF_RECORDS    = 1024;
29      private static final long DEF_MULTIPLIER = 987769338L;
30      private static final long DEF_DIVISOR    = (1L << 32) - 1L;
31  
32  
33      private final long minuend;
34  
35  
36      /**
37       * Constructor.
38       *
39       * <ul>
40       * <li>record length must be greater than 0.
41       * <li>multiplier must be greater than 1.
42       * <li>divisor must be greater than 1.
43       * </ul>
44       *
45       * <p>If you want 32-bit uniformly distributed random numbers,
46       * the divisor must be 2**32, but you can compromise with 2**32 -1.
47       *
48       * @param recLen records length
49       * @param mulArg multiplier
50       * @param divArg divisor
51       * @throws IllegalArgumentException illegal argument
52       */
53      public Cmwc(int recLen, long mulArg, long divArg) throws IllegalArgumentException {
54          super(recLen, mulArg, divArg);
55          this.minuend = divArg - 1;
56          return;
57      }
58  
59      /**
60       * Constructor.
61       *
62       * <ul>
63       * <li>Default record length = 1024
64       * <li>Default multiplier value = 987769338
65       * <li>Default divisor value = 2**32 - 1
66       * </ul>
67       *
68       * <p>* Caution : If you don't provide your entropy to seeds,
69       * it takes over million trials until the seed is scrambled.
70       *
71       * @throws IllegalArgumentException illegal argument
72       * @see <a href="http://digitalcommons.wayne.edu/cgi/viewcontent.cgi?article=1725&context=jmasm">
73       * Random Number Generators
74       * </a>
75       */
76      public Cmwc() throws IllegalArgumentException {
77          this(DEF_RECORDS, DEF_MULTIPLIER, DEF_DIVISOR);
78          // this(4, 987654978L, (1L << 32) - 1L);
79          // this(8, 987651670L, (1L << 32) - 1L);
80          // this(2048, 1047570L, (1L << 32) - 1L);
81          // this(4096, 18782L, (1L << 32) - 1L);
82          // this(42658, 15455296L, 1L << 32);
83          return;
84      }
85  
86  
87      /**
88       * {@inheritDoc}
89       *
90       * @param tVal {@inheritDoc}
91       * @return {@inheritDoc}
92       */
93      @Override
94      protected int funcRndFromTval(long tVal) {
95          long lVal = this.minuend - super.funcRndFromTval(tVal);
96          int result = (int) lVal;
97          return result;
98      }
99  
100 }