1
2
3
4
5
6 package io.github.olyutorskii.aletojio.rng.lcg;
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 public abstract class AbstractLcg {
22
23
24 protected static final long MASK_B31 = (1L << 31) - 1L;
25
26 protected static final long MASK_B32 = (1L << 32) - 1L;
27
28 private static final long DEF_SEED = 0x01L;
29
30 private static final String ERRMSG_MUL = "multiplier must be 1 or greater";
31 private static final String ERRMSG_INC = "increment must be 0 or greater";
32 private static final String ERRMSG_MOD = "modulus must be 2 or greater";
33 private static final String ERRMSG_SEED = "seed must not be negative";
34
35
36 private long seed;
37
38 private final long multiplier;
39 private final long increment;
40 private final long modulus;
41
42
43 private final long modMask;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 protected AbstractLcg(long mulArg, long incArg, long modArg)
61 throws IllegalArgumentException {
62 super();
63
64 if (mulArg < 1) {
65 throw new IllegalArgumentException(ERRMSG_MUL);
66 }
67
68 if (incArg < 0) {
69 throw new IllegalArgumentException(ERRMSG_INC);
70 }
71
72
73 if (modArg < 2) {
74 throw new IllegalArgumentException(ERRMSG_MOD);
75 }
76
77 this.multiplier = mulArg;
78 this.increment = incArg;
79 this.modulus = modArg;
80
81 this.modMask = calcModMask(this.modulus);
82
83 this.seed = DEF_SEED;
84
85 return;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 static long calcModMask(long mod) {
105 if (mod == 0L) return 0L;
106
107 long dec = mod - 1L;
108 boolean pow2Mod = (mod & dec) == 0L;
109
110 long newMask;
111 if (pow2Mod) {
112 newMask = dec;
113 } else {
114 newMask = 0L;
115 }
116
117 return newMask;
118 }
119
120
121
122
123
124
125
126
127
128 protected int nextIntImpl() {
129 this.seed = nextSeed();
130 int result = seedToResult();
131 return result;
132 }
133
134
135
136
137
138
139
140 protected long nextSeed() throws IllegalStateException {
141 long dividend = this.seed * this.multiplier + this.increment;
142
143 long nextSeed;
144 if (this.modMask == 0) {
145 if (dividend < 0) {
146 throw new IllegalStateException();
147 }
148 nextSeed = dividend % this.modulus;
149 } else {
150 nextSeed = dividend & this.modMask;
151 }
152
153 return nextSeed;
154 }
155
156
157
158
159
160
161 protected abstract int seedToResult();
162
163
164
165
166
167
168
169 public void setSeed(long seedArg) throws IllegalArgumentException {
170 if (seedArg < 0) {
171 throw new IllegalArgumentException(ERRMSG_SEED);
172 }
173
174 this.seed = seedArg;
175
176 return;
177 }
178
179
180
181
182
183
184 public long getSeed() {
185 return this.seed;
186 }
187
188 }