1
2
3
4
5
6 package io.github.olyutorskii.aletojio.rng.fibo;
7
8 import io.github.olyutorskii.aletojio.rng.RndInt32;
9 import java.util.Objects;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public class LagFib implements RndInt32 {
38
39 private static final int INITIAL_ODD = 0x01;
40
41 private static final String ERRMSG_POSARG = "Generation must be positive";
42 private static final String ERRMSG_ORDER = "Older generation must be greater than younger";
43 private static final String ERRMSG_ODDSEED = "At least one of the seeds must be odd number";
44 private static final String ERRMSG_SEEDLEN = "Unmatch seeds length";
45
46
47 private final int[] recRing;
48 private final int recSize;
49
50 private int recentIdx;
51
52 private final int genYng;
53 private final int genOld;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public LagFib(int genYounger, int genOlder)
69 throws IndexOutOfBoundsException, IllegalArgumentException {
70 super();
71
72 if (genYounger < 1) {
73 throw new IndexOutOfBoundsException(ERRMSG_POSARG);
74 }
75 if (genYounger >= genOlder) {
76 throw new IllegalArgumentException(ERRMSG_ORDER);
77 }
78
79 this.genYng = genYounger;
80 this.genOld = genOlder;
81
82 this.recRing = new int[this.genOld];
83 this.recSize = this.recRing.length;
84
85 this.recentIdx = 0;
86
87 int lastIdx = this.recSize - 1;
88 this.recRing[lastIdx] = INITIAL_ODD;
89
90 assert hasOdd(this.recRing);
91
92 return;
93 }
94
95
96
97
98
99
100
101
102
103 public static boolean hasOdd(int... iVec) throws NullPointerException {
104 Objects.requireNonNull(iVec);
105
106 for (int iSeed : iVec) {
107 boolean isOdd = (iSeed & 0b1) != 0;
108 if (isOdd) {
109 return true;
110 }
111 }
112
113 return false;
114 }
115
116
117
118
119
120
121
122
123 protected void checkSeeds(int... initVec) throws IllegalArgumentException {
124 if (!hasOdd(initVec)) {
125 throw new IllegalArgumentException(ERRMSG_ODDSEED);
126 }
127 return;
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142 public void setSeed(int... initVec)
143 throws NullPointerException, IndexOutOfBoundsException, IllegalArgumentException {
144 Objects.requireNonNull(initVec);
145
146 if (initVec.length != this.recSize) {
147 throw new IndexOutOfBoundsException(ERRMSG_SEEDLEN);
148 }
149
150 checkSeeds(initVec);
151
152 for (int ct = 0; ct < initVec.length; ct++) {
153 int idx = this.recentIdx + ct;
154 if (idx >= this.recSize) {
155 idx -= this.recSize;
156 }
157 this.recRing[idx] = initVec[ct];
158 }
159
160 return;
161 }
162
163
164
165
166
167
168
169 private int genValue(int genNo) {
170 assert 1 <= genNo;
171 assert genNo <= this.recSize;
172
173 int rawIdx = this.recentIdx + genNo - 1;
174 if (rawIdx >= this.recSize) {
175 rawIdx -= this.recSize;
176 }
177
178 int result = this.recRing[rawIdx];
179 return result;
180 }
181
182
183
184
185
186
187
188
189
190
191 protected int binOp(int tap1, int tap2) {
192 int result = tap1 + tap2;
193 return result;
194 }
195
196
197
198
199
200
201 @Override
202 public int nextInt32() {
203 int valYng = genValue(this.genYng);
204 int valOld = genValue(this.genOld);
205
206 int result = binOp(valYng, valOld);
207
208 this.recentIdx--;
209 if (this.recentIdx < 0) {
210 int lastIdx = this.recSize - 1;
211 this.recentIdx = lastIdx;
212 }
213 this.recRing[this.recentIdx] = result;
214
215 return result;
216 }
217
218 }