1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.examples.stress;
18
19 import org.apache.commons.rng.UniformRandomProvider;
20 import org.apache.commons.rng.core.source32.IntProvider;
21 import org.apache.commons.rng.core.source32.RandomIntSource;
22 import org.apache.commons.rng.core.source64.RandomLongSource;
23 import org.apache.commons.rng.simple.RandomSource;
24 import org.junit.jupiter.api.Assertions;
25 import org.junit.jupiter.api.Test;
26
27 import java.io.ByteArrayOutputStream;
28 import java.io.DataOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.nio.ByteOrder;
32 import java.util.function.BiConsumer;
33 import java.util.function.UnaryOperator;
34
35
36
37
38 class RngDataOutputTest {
39
40
41
42 interface RngDataOutputFactory {
43
44
45
46
47
48
49
50
51 RngDataOutput create(OutputStream out, int size, ByteOrder byteOrder);
52 }
53
54 @Test
55 void testIntBigEndian() throws IOException {
56 assertRngOutput(RandomSource.PCG_MCG_XSH_RS_32,
57 UnaryOperator.identity(),
58 RngDataOutputTest::writeInt,
59 RngDataOutput::ofInt, ByteOrder.BIG_ENDIAN);
60 }
61
62 @Test
63 void testIntLittleEndian() throws IOException {
64 assertRngOutput(RandomSource.PCG_MCG_XSH_RS_32,
65 RNGUtils::createReverseBytesProvider,
66 RngDataOutputTest::writeInt,
67 RngDataOutput::ofInt, ByteOrder.LITTLE_ENDIAN);
68 }
69
70 @Test
71 void testLongBigEndian() throws IOException {
72 assertRngOutput(RandomSource.SPLIT_MIX_64,
73 UnaryOperator.identity(),
74 RngDataOutputTest::writeLong,
75 RngDataOutput::ofLong, ByteOrder.BIG_ENDIAN);
76 }
77
78 @Test
79 void testLongLittleEndian() throws IOException {
80 assertRngOutput(RandomSource.SPLIT_MIX_64,
81 RNGUtils::createReverseBytesProvider,
82 RngDataOutputTest::writeLong,
83 RngDataOutput::ofLong, ByteOrder.LITTLE_ENDIAN);
84 }
85
86 @Test
87 void testLongAsHLIntBigEndian() throws IOException {
88 assertRngOutput(RandomSource.SPLIT_MIX_64,
89
90
91 rng -> new HiLoCachingIntProvider(rng),
92 RngDataOutputTest::writeInt,
93 RngDataOutput::ofLongAsHLInt, ByteOrder.BIG_ENDIAN);
94 }
95
96 @Test
97 void testLongAsHLIntLittleEndian() throws IOException {
98 assertRngOutput(RandomSource.SPLIT_MIX_64,
99
100
101 rng -> new HiLoCachingIntProvider(rng) {
102 @Override
103 public int next() {
104 return Integer.reverseBytes(super.next());
105 }
106 },
107 RngDataOutputTest::writeInt,
108 RngDataOutput::ofLongAsHLInt, ByteOrder.LITTLE_ENDIAN);
109 }
110
111
112 @Test
113 void testLongAsLHIntBigEndian() throws IOException {
114 assertRngOutput(RandomSource.SPLIT_MIX_64,
115
116
117 rng -> new LoHiCachingIntProvider(rng),
118 RngDataOutputTest::writeInt,
119 RngDataOutput::ofLongAsLHInt, ByteOrder.BIG_ENDIAN);
120 }
121
122 @Test
123 void testLongAsLHIntLittleEndian() throws IOException {
124 assertRngOutput(RandomSource.SPLIT_MIX_64,
125
126
127 rng -> new LoHiCachingIntProvider(rng) {
128 @Override
129 public int next() {
130 return Integer.reverseBytes(super.next());
131 }
132 },
133 RngDataOutputTest::writeInt,
134 RngDataOutput::ofLongAsLHInt, ByteOrder.LITTLE_ENDIAN);
135 }
136
137 private static void writeInt(DataOutputStream sink, UniformRandomProvider rng) {
138 try {
139 sink.writeInt(rng.nextInt());
140 } catch (IOException e) {
141 Assertions.fail();
142 }
143 }
144
145 private static void writeLong(DataOutputStream sink, UniformRandomProvider rng) {
146 try {
147 sink.writeLong(rng.nextLong());
148 } catch (IOException e) {
149 Assertions.fail();
150 }
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 private static void assertRngOutput(RandomSource source,
170 UnaryOperator<UniformRandomProvider> rngConverter,
171 BiConsumer<DataOutputStream, UniformRandomProvider> pipe,
172 RngDataOutputFactory factory,
173 ByteOrder byteOrder) throws IOException {
174 final long seed = RandomSource.createLong();
175 UniformRandomProvider rng1 = source.create(seed);
176 UniformRandomProvider rng2 = source.create(seed);
177 final int size = 37;
178 for (int repeats = 1; repeats <= 2; repeats++) {
179 byte[] expected = createBytes(rng1, size, repeats, rngConverter, pipe);
180 byte[] actual = writeRngOutput(rng2, size, repeats, byteOrder, factory);
181 Assertions.assertArrayEquals(expected, actual);
182 }
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196 private static byte[] createBytes(UniformRandomProvider rng, int size, int repeats,
197 UnaryOperator<UniformRandomProvider> rngConverter,
198 BiConsumer<DataOutputStream, UniformRandomProvider> pipe) throws IOException {
199 UniformRandomProvider rng2 = rngConverter.apply(rng);
200
201 if (rng instanceof RandomLongSource && rng2 instanceof RandomIntSource) {
202 size *= 2;
203 }
204 ByteArrayOutputStream out = new ByteArrayOutputStream();
205 try (DataOutputStream sink = new DataOutputStream(out)) {
206 for (int j = 0; j < repeats; j++) {
207 for (int i = 0; i < size; i++) {
208 pipe.accept(sink, rng2);
209 }
210 }
211 }
212 return out.toByteArray();
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226 private static byte[] writeRngOutput(UniformRandomProvider rng, int size, int repeats,
227 ByteOrder byteOrder, RngDataOutputFactory factory) throws IOException {
228 ByteArrayOutputStream out = new ByteArrayOutputStream();
229 try (RngDataOutput sink = factory.create(out, size, byteOrder)) {
230 for (int j = 0; j < repeats; j++) {
231 sink.write(rng);
232 }
233 }
234 return out.toByteArray();
235 }
236
237 private static class LoHiCachingIntProvider extends IntProvider {
238 private long source = -1;
239 private final UniformRandomProvider rng;
240
241 LoHiCachingIntProvider(UniformRandomProvider rng) {
242 this.rng = rng;
243 }
244
245 @Override
246 public int next() {
247 long next = source;
248 if (next < 0) {
249
250 next = rng.nextLong();
251
252 source = next >>> 32;
253
254 return (int) next;
255 }
256 final int v = (int) next;
257
258 source = -1;
259 return v;
260 }
261 }
262
263 private static class HiLoCachingIntProvider extends IntProvider {
264 private long source = -1;
265 private final UniformRandomProvider rng;
266
267 HiLoCachingIntProvider(UniformRandomProvider rng) {
268 this.rng = rng;
269 }
270
271 @Override
272 public int next() {
273 long next = source;
274 if (next < 0) {
275
276 next = rng.nextLong();
277
278 source = next & 0xffff_ffffL;
279
280 return (int) (next >>> 32);
281 }
282 final int v = (int) next;
283
284 source = -1;
285 return v;
286 }
287 }
288 }