1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.core.util;
18
19 import java.nio.ByteBuffer;
20 import java.nio.ByteOrder;
21 import java.util.Arrays;
22 import java.util.concurrent.ThreadLocalRandom;
23 import java.util.stream.IntStream;
24 import java.util.stream.LongStream;
25 import org.apache.commons.math3.util.Precision;
26 import org.junit.jupiter.api.Assertions;
27 import org.junit.jupiter.api.RepeatedTest;
28 import org.junit.jupiter.api.Test;
29 import org.junit.jupiter.params.ParameterizedTest;
30 import org.junit.jupiter.params.provider.MethodSource;
31
32
33
34
35 class NumberFactoryTest {
36
37 private static final int INT_SIZE = Integer.BYTES;
38
39 private static final int LONG_SIZE = Long.BYTES;
40
41
42 private static final long[] LONG_TEST_VALUES = new long[] {0L, 1L, -1L, 19337L, 1234567891011213L,
43 -11109876543211L, Integer.MAX_VALUE, Integer.MIN_VALUE, Long.MAX_VALUE,
44 Long.MIN_VALUE, 0x9e3779b97f4a7c13L};
45
46 private static final int[] INT_TEST_VALUES = new int[] {0, 1, -1, 19337, 1234567891, -1110987656,
47 Integer.MAX_VALUE, Integer.MIN_VALUE, 0x9e3779b9};
48
49
50
51
52
53
54 static LongStream longTestValues() {
55 return Arrays.stream(LONG_TEST_VALUES);
56 }
57
58
59
60
61
62
63 static IntStream intTestValues() {
64 return Arrays.stream(INT_TEST_VALUES);
65 }
66
67 @ParameterizedTest
68 @MethodSource(value = {"intTestValues"})
69 void testMakeBooleanFromInt(int v) {
70
71 final boolean b1 = NumberFactory.makeBoolean(v);
72 final boolean b2 = NumberFactory.makeBoolean(~v);
73 Assertions.assertNotEquals(b1, b2);
74 }
75
76 @ParameterizedTest
77 @MethodSource(value = {"longTestValues"})
78 void testMakeBooleanFromLong(long v) {
79
80 final boolean b1 = NumberFactory.makeBoolean(v);
81 final boolean b2 = NumberFactory.makeBoolean(~v);
82 Assertions.assertNotEquals(b1, b2);
83 }
84
85 @Test
86 void testMakeIntFromLong() {
87
88 Assertions.assertEquals(0xffffffff, NumberFactory.makeInt(0xffffffff00000000L));
89 Assertions.assertEquals(0x00000000, NumberFactory.makeInt(0xffffffffffffffffL));
90 Assertions.assertEquals(0xffffffff, NumberFactory.makeInt(0x00000000ffffffffL));
91 Assertions.assertEquals(0x00000000, NumberFactory.makeInt(0x0000000000000000L));
92 Assertions.assertEquals(0x0f0f0f0f, NumberFactory.makeInt(0x0f0f0f0f00000000L));
93 Assertions.assertEquals(0xf0f0f0f0, NumberFactory.makeInt(0x00000000f0f0f0f0L));
94 Assertions.assertEquals(0x00000000, NumberFactory.makeInt(0x0f0f0f0f0f0f0f0fL));
95 Assertions.assertEquals(0xffffffff, NumberFactory.makeInt(0x0f0f0f0ff0f0f0f0L));
96 }
97
98 @ParameterizedTest
99 @MethodSource(value = {"longTestValues"})
100 void testExtractLoExtractHi(long v) {
101 final int vL = NumberFactory.extractLo(v);
102 final int vH = NumberFactory.extractHi(v);
103
104 final long actual = (((long) vH) << 32) | (vL & 0xffffffffL);
105 Assertions.assertEquals(v, actual);
106 }
107
108 @ParameterizedTest
109 @MethodSource(value = {"longTestValues"})
110 void testLong2Long(long v) {
111 final int vL = NumberFactory.extractLo(v);
112 final int vH = NumberFactory.extractHi(v);
113
114 Assertions.assertEquals(v, NumberFactory.makeLong(vH, vL));
115 }
116
117 @Test
118 void testLongToByteArraySignificanceOrder() {
119
120 long value = 1;
121 for (int i = 0; i < LONG_SIZE; i++) {
122 final byte[] b = NumberFactory.makeByteArray(value);
123 for (int j = 0; j < LONG_SIZE; j++) {
124
125 Assertions.assertEquals(b[j] != 0, j == i);
126 }
127
128 value <<= 8;
129 }
130 }
131
132 @ParameterizedTest
133 @MethodSource(value = {"longTestValues"})
134 void testLongToBytesIsLittleEndian(long v) {
135 final ByteBuffer bb = ByteBuffer.allocate(LONG_SIZE).order(ByteOrder.LITTLE_ENDIAN);
136 bb.putLong(v);
137 Assertions.assertArrayEquals(bb.array(), NumberFactory.makeByteArray(v));
138 }
139
140 @RepeatedTest(value = 5)
141 void testByteArrayToLongArrayIsLittleEndian() {
142 final int n = 5;
143 byte[] bytes = new byte[n * LONG_SIZE];
144 ThreadLocalRandom.current().nextBytes(bytes);
145 final ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
146 final long[] data = NumberFactory.makeLongArray(bytes);
147 for (int i = 0; i < n; i++) {
148 Assertions.assertEquals(bb.getLong(), data[i]);
149 }
150 Assertions.assertArrayEquals(bytes, NumberFactory.makeByteArray(data));
151 }
152
153 @ParameterizedTest
154 @MethodSource(value = {"longTestValues"})
155 void testLongFromByteArray2Long(long expected) {
156 final byte[] b = NumberFactory.makeByteArray(expected);
157 Assertions.assertEquals(expected, NumberFactory.makeLong(b));
158 }
159
160 @Test
161 void testLongArrayFromByteArray2LongArray() {
162 final byte[] b = NumberFactory.makeByteArray(LONG_TEST_VALUES);
163 Assertions.assertArrayEquals(LONG_TEST_VALUES, NumberFactory.makeLongArray(b));
164 }
165
166 @ParameterizedTest
167 @MethodSource(value = {"longTestValues"})
168 void testLongArrayToByteArrayMatchesLongToByteArray(long v) {
169
170 final byte[] b1 = NumberFactory.makeByteArray(v);
171 final byte[] b2 = NumberFactory.makeByteArray(new long[] {v});
172 Assertions.assertArrayEquals(b1, b2);
173 }
174
175 @Test
176 void testIntToByteArraySignificanceOrder() {
177
178 int value = 1;
179 for (int i = 0; i < INT_SIZE; i++) {
180 final byte[] b = NumberFactory.makeByteArray(value);
181 for (int j = 0; j < INT_SIZE; j++) {
182
183 Assertions.assertEquals(b[j] != 0, j == i);
184 }
185
186 value <<= 8;
187 }
188 }
189
190 @ParameterizedTest
191 @MethodSource(value = {"intTestValues"})
192 void testIntToBytesIsLittleEndian(int v) {
193 final ByteBuffer bb = ByteBuffer.allocate(INT_SIZE).order(ByteOrder.LITTLE_ENDIAN);
194 bb.putInt(v);
195 Assertions.assertArrayEquals(bb.array(), NumberFactory.makeByteArray(v));
196 }
197
198 @RepeatedTest(value = 5)
199 void testByteArrayToIntArrayIsLittleEndian() {
200 final int n = 5;
201 byte[] bytes = new byte[n * INT_SIZE];
202 ThreadLocalRandom.current().nextBytes(bytes);
203 final ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
204 final int[] data = NumberFactory.makeIntArray(bytes);
205 for (int i = 0; i < n; i++) {
206 Assertions.assertEquals(bb.getInt(), data[i]);
207 }
208 Assertions.assertArrayEquals(bytes, NumberFactory.makeByteArray(data));
209 }
210
211 @ParameterizedTest
212 @MethodSource(value = {"intTestValues"})
213 void testIntFromByteArray2Int(int expected) {
214 final byte[] b = NumberFactory.makeByteArray(expected);
215 Assertions.assertEquals(expected, NumberFactory.makeInt(b));
216 }
217
218 @Test
219 void testIntArrayFromByteArray2IntArray() {
220 final byte[] b = NumberFactory.makeByteArray(INT_TEST_VALUES);
221 Assertions.assertArrayEquals(INT_TEST_VALUES, NumberFactory.makeIntArray(b));
222 }
223
224 @ParameterizedTest
225 @MethodSource(value = {"intTestValues"})
226 void testIntArrayToByteArrayMatchesIntToByteArray(int v) {
227
228 final byte[] b1 = NumberFactory.makeByteArray(v);
229 final byte[] b2 = NumberFactory.makeByteArray(new int[] {v});
230 Assertions.assertArrayEquals(b1, b2);
231 }
232
233 @Test
234 void testMakeIntPrecondition1() {
235 for (int i = 0; i <= 10; i++) {
236 final byte[] bytes = new byte[i];
237 if (i != INT_SIZE) {
238 Assertions.assertThrows(IllegalArgumentException.class,
239 () -> NumberFactory.makeInt(bytes));
240 } else {
241 Assertions.assertEquals(0, NumberFactory.makeInt(bytes));
242 }
243 }
244 }
245
246 @Test
247 void testMakeIntArrayPrecondition1() {
248 for (int i = 0; i <= 20; i++) {
249 final byte[] bytes = new byte[i];
250 if (i != 0 && i % INT_SIZE != 0) {
251 Assertions.assertThrows(IllegalArgumentException.class,
252 () -> NumberFactory.makeIntArray(bytes));
253 } else {
254 Assertions.assertArrayEquals(new int[i / INT_SIZE], NumberFactory.makeIntArray(bytes));
255 }
256 }
257 }
258
259 @Test
260 void testMakeLongPrecondition1() {
261 for (int i = 0; i <= 10; i++) {
262 final byte[] bytes = new byte[i];
263 if (i != LONG_SIZE) {
264 Assertions.assertThrows(IllegalArgumentException.class,
265 () -> NumberFactory.makeLong(bytes));
266 } else {
267 Assertions.assertEquals(0L, NumberFactory.makeLong(bytes));
268 }
269 }
270 }
271
272 @Test
273 void testMakeLongArrayPrecondition1() {
274 for (int i = 0; i <= 20; i++) {
275 final byte[] bytes = new byte[i];
276 if (i != 0 && i % LONG_SIZE != 0) {
277 Assertions.assertThrows(IllegalArgumentException.class,
278 () -> NumberFactory.makeLongArray(bytes));
279 } else {
280 Assertions.assertArrayEquals(new long[i / LONG_SIZE], NumberFactory.makeLongArray(bytes));
281 }
282 }
283 }
284
285
286
287
288
289 @Test
290 void testFloatGenerationMethods() {
291 final int allBits = 0xffffffff;
292
293
294 assertCloseToNotAbove1((allBits >>> 9) * 0x1.0p-23f, 2);
295 assertCloseToNotAbove1((allBits >>> 8) * 0x1.0p-24f, 1);
296 assertCloseToNotAbove1(Float.intBitsToFloat(0x7f << 23 | allBits >>> 9) - 1.0f, 2);
297
298 final int noBits = 0;
299 Assertions.assertEquals(0.0f, (noBits >>> 9) * 0x1.0p-23f);
300 Assertions.assertEquals(0.0f, (noBits >>> 8) * 0x1.0p-24f);
301 Assertions.assertEquals(0.0f, Float.intBitsToFloat(0x7f << 23 | noBits >>> 9) - 1.0f);
302 }
303
304
305
306
307
308 @Test
309 void testDoubleGenerationMethods() {
310 final long allBits = 0xffffffffffffffffL;
311
312
313 assertCloseToNotAbove1((allBits >>> 12) * 0x1.0p-52d, 2);
314 assertCloseToNotAbove1((allBits >>> 11) * 0x1.0p-53d, 1);
315 assertCloseToNotAbove1(Double.longBitsToDouble(0x3ffL << 52 | allBits >>> 12) - 1.0, 2);
316
317 final long noBits = 0;
318 Assertions.assertEquals(0.0, (noBits >>> 12) * 0x1.0p-52d);
319 Assertions.assertEquals(0.0, (noBits >>> 11) * 0x1.0p-53d);
320 Assertions.assertEquals(0.0, Double.longBitsToDouble(0x3ffL << 52 | noBits >>> 12) - 1.0);
321 }
322
323 @Test
324 void testMakeDoubleFromLong() {
325 final long allBits = 0xffffffffffffffffL;
326 final long noBits = 0;
327
328 assertCloseToNotAbove1(NumberFactory.makeDouble(allBits), 1);
329 Assertions.assertEquals(0.0, NumberFactory.makeDouble(noBits));
330 }
331
332 @Test
333 void testMakeDoubleFromIntInt() {
334 final int allBits = 0xffffffff;
335 final int noBits = 0;
336
337 assertCloseToNotAbove1(NumberFactory.makeDouble(allBits, allBits), 1);
338 Assertions.assertEquals(0.0, NumberFactory.makeDouble(noBits, noBits));
339 }
340
341 @Test
342 void testMakeFloatFromInt() {
343 final int allBits = 0xffffffff;
344 final int noBits = 0;
345
346 assertCloseToNotAbove1(NumberFactory.makeFloat(allBits), 1);
347 Assertions.assertEquals(0.0f, NumberFactory.makeFloat(noBits));
348 }
349
350
351
352
353
354
355
356
357
358
359 private static void assertCloseToNotAbove1(float value, int maxUlps) {
360 Assertions.assertTrue(value <= 1.0f, "Not <= 1.0f");
361 Assertions.assertTrue(Precision.equals(1.0f, value, maxUlps),
362 () -> "Not equal to 1.0f within units of least precision: " + maxUlps);
363 }
364
365
366
367
368
369
370
371
372
373
374 private static void assertCloseToNotAbove1(double value, int maxUlps) {
375 Assertions.assertTrue(value <= 1.0, "Not <= 1.0");
376 Assertions.assertTrue(Precision.equals(1.0, value, maxUlps),
377 () -> "Not equal to 1.0 within units of least precision: " + maxUlps);
378 }
379 }