View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.core.util;
18  
19  import org.apache.commons.math3.util.Precision;
20  import org.junit.Assert;
21  import org.junit.Test;
22  
23  /**
24   * Tests for the {@link NumberFactory}.
25   */
26  public class NumberFactoryTest {
27      /** sizeof(int). */
28      private static final int INT_SIZE = 4;
29      /** sizeof(long). */
30      private static final int LONG_SIZE = 8;
31  
32      /** Test values. */
33      private static final long[] LONG_TEST_VALUES = new long[] {0L, 1L, -1L, 19337L, 1234567891011213L,
34          -11109876543211L, Long.valueOf(Integer.MAX_VALUE), Long.valueOf(Integer.MIN_VALUE), Long.MAX_VALUE,
35          Long.MIN_VALUE, 0x9e3779b97f4a7c13L};
36      /** Test values. */
37      private static final int[] INT_TEST_VALUES = new int[] {0, 1, -1, 19337, 1234567891, -1110987656,
38          Integer.MAX_VALUE, Integer.MIN_VALUE, 0x9e3779b9};
39  
40      @Test
41      public void testMakeBooleanFromInt() {
42          // Test if the bit is set differently then the booleans are opposite
43          final boolean b1 = NumberFactory.makeBoolean(0);
44          final boolean b2 = NumberFactory.makeBoolean(0xffffffff);
45          Assert.assertNotEquals(b1, b2);
46      }
47  
48      @Test
49      public void testMakeBooleanFromLong() {
50          // Test if the bit is set differently then the booleans are opposite
51          final boolean b1 = NumberFactory.makeBoolean(0L);
52          final boolean b2 = NumberFactory.makeBoolean(0xffffffffffffffffL);
53          Assert.assertNotEquals(b1, b2);
54      }
55  
56      @Test
57      public void testMakeIntFromLong() {
58          // Test the high order bits and low order bits are xor'd together
59          Assert.assertEquals(0xffffffff, NumberFactory.makeInt(0xffffffff00000000L));
60          Assert.assertEquals(0x00000000, NumberFactory.makeInt(0xffffffffffffffffL));
61          Assert.assertEquals(0xffffffff, NumberFactory.makeInt(0x00000000ffffffffL));
62          Assert.assertEquals(0x00000000, NumberFactory.makeInt(0x0000000000000000L));
63          Assert.assertEquals(0x0f0f0f0f, NumberFactory.makeInt(0x0f0f0f0f00000000L));
64          Assert.assertEquals(0xf0f0f0f0, NumberFactory.makeInt(0x00000000f0f0f0f0L));
65          Assert.assertEquals(0x00000000, NumberFactory.makeInt(0x0f0f0f0f0f0f0f0fL));
66          Assert.assertEquals(0xffffffff, NumberFactory.makeInt(0x0f0f0f0ff0f0f0f0L));
67      }
68  
69      @Test
70      public void testExtractLoExtractHi() {
71          for (long v : LONG_TEST_VALUES) {
72              final int vL = NumberFactory.extractLo(v);
73              final int vH = NumberFactory.extractHi(v);
74  
75              final long actual = (((long) vH) << 32) | (vL & 0xffffffffL);
76              Assert.assertEquals(v, actual);
77          }
78      }
79  
80      @Test
81      public void testLong2Long() {
82          for (long v : LONG_TEST_VALUES) {
83              final int vL = NumberFactory.extractLo(v);
84              final int vH = NumberFactory.extractHi(v);
85  
86              Assert.assertEquals(v, NumberFactory.makeLong(vH, vL));
87          }
88      }
89  
90      @Test
91      public void testLongToByteArraySignificanceOrder() {
92          // Start at the least significant bit
93          long value = 1;
94          for (int i = 0; i < LONG_SIZE; i++) {
95              final byte[] b = NumberFactory.makeByteArray(value);
96              for (int j = 0; j < LONG_SIZE; j++) {
97                  // Only one byte should be non zero
98                  Assert.assertEquals(b[j] != 0, j == i);
99              }
100             // Shift to the next byte
101             value <<= 8;
102         }
103     }
104 
105     @Test
106     public void testLongFromByteArray2Long() {
107         for (long expected : LONG_TEST_VALUES) {
108             final byte[] b = NumberFactory.makeByteArray(expected);
109             Assert.assertEquals(expected, NumberFactory.makeLong(b));
110         }
111     }
112 
113     @Test
114     public void testLongArrayFromByteArray2LongArray() {
115         final byte[] b = NumberFactory.makeByteArray(LONG_TEST_VALUES);
116         Assert.assertArrayEquals(LONG_TEST_VALUES, NumberFactory.makeLongArray(b));
117     }
118 
119     @Test
120     public void testLongArrayToByteArrayMatchesLongToByteArray() {
121         // Test individually the bytes are the same as the array conversion
122         for (int i = 0; i < LONG_TEST_VALUES.length; i++) {
123             final byte[] b1 = NumberFactory.makeByteArray(LONG_TEST_VALUES[i]);
124             final byte[] b2 = NumberFactory.makeByteArray(new long[] {LONG_TEST_VALUES[i]});
125             Assert.assertArrayEquals(b1, b2);
126         }
127     }
128 
129     @Test
130     public void testIntToByteArraySignificanceOrder() {
131         // Start at the least significant bit
132         int value = 1;
133         for (int i = 0; i < INT_SIZE; i++) {
134             final byte[] b = NumberFactory.makeByteArray(value);
135             for (int j = 0; j < INT_SIZE; j++) {
136                 // Only one byte should be non zero
137                 Assert.assertEquals(b[j] != 0, j == i);
138             }
139             // Shift to the next byte
140             value <<= 8;
141         }
142     }
143 
144     @Test
145     public void testIntFromByteArray2Int() {
146         for (int expected : INT_TEST_VALUES) {
147             final byte[] b = NumberFactory.makeByteArray(expected);
148             Assert.assertEquals(expected, NumberFactory.makeInt(b));
149         }
150     }
151 
152     @Test
153     public void testIntArrayFromByteArray2IntArray() {
154         final byte[] b = NumberFactory.makeByteArray(INT_TEST_VALUES);
155         Assert.assertArrayEquals(INT_TEST_VALUES, NumberFactory.makeIntArray(b));
156     }
157 
158     @Test
159     public void testIntArrayToByteArrayMatchesIntToByteArray() {
160         // Test individually the bytes are the same as the array conversion
161         for (int i = 0; i < INT_TEST_VALUES.length; i++) {
162             final byte[] b1 = NumberFactory.makeByteArray(INT_TEST_VALUES[i]);
163             final byte[] b2 = NumberFactory.makeByteArray(new int[] {INT_TEST_VALUES[i]});
164             Assert.assertArrayEquals(b1, b2);
165         }
166     }
167 
168     @Test
169     public void testMakeIntPrecondition1() {
170         for (int i = 0; i <= 10; i++) {
171             try {
172                 NumberFactory.makeInt(new byte[i]);
173                 if (i != INT_SIZE) {
174                     Assert.fail("Exception expected");
175                 }
176             } catch (IllegalArgumentException e) {
177                 // Expected.
178             }
179         }
180     }
181 
182     @Test
183     public void testMakeIntArrayPrecondition1() {
184         for (int i = 0; i <= 20; i++) {
185             try {
186                 NumberFactory.makeIntArray(new byte[i]);
187                 if (i != 0 && (i % INT_SIZE != 0)) {
188                     Assert.fail("Exception expected");
189                 }
190             } catch (IllegalArgumentException e) {
191                 // Expected.
192             }
193         }
194     }
195 
196     @Test
197     public void testMakeLongPrecondition1() {
198         for (int i = 0; i <= 10; i++) {
199             try {
200                 NumberFactory.makeLong(new byte[i]);
201                 if (i != LONG_SIZE) {
202                     Assert.fail("Exception expected");
203                 }
204             } catch (IllegalArgumentException e) {
205                 // Expected.
206             }
207         }
208     }
209 
210     @Test
211     public void testMakeLongArrayPrecondition1() {
212         for (int i = 0; i <= 20; i++) {
213             try {
214                 NumberFactory.makeLongArray(new byte[i]);
215                 if (i != 0 && (i % LONG_SIZE != 0)) {
216                     Assert.fail("Exception expected");
217                 }
218             } catch (IllegalArgumentException e) {
219                 // Expected.
220             }
221         }
222     }
223 
224     /**
225      * Test different methods for generation of a {@code float} from a {@code int}. The output
226      * value should be in the range between 0 and 1.
227      */
228     @Test
229     public void testFloatGenerationMethods() {
230         final int allBits = 0xffffffff;
231 
232         // Not capable of generating 1. Set the delta with 1 or 2 ULP of 1.
233         assertCloseToNotAbove1((allBits >>> 9) * 0x1.0p-23f, 2);
234         assertCloseToNotAbove1((allBits >>> 8) * 0x1.0p-24f, 1);
235         assertCloseToNotAbove1(Float.intBitsToFloat(0x7f << 23 | allBits >>> 9) - 1.0f, 2);
236 
237         final int noBits = 0;
238         Assert.assertEquals(0.0f, (noBits >>> 9) * 0x1.0p-23f, 0);
239         Assert.assertEquals(0.0f, (noBits >>> 8) * 0x1.0p-24f, 0);
240         Assert.assertEquals(0.0f, Float.intBitsToFloat(0x7f << 23 | noBits >>> 9) - 1.0f, 0);
241     }
242 
243     /**
244      * Test different methods for generation of a {@code double} from a {@code long}. The output
245      * value should be in the range between 0 and 1.
246      */
247     @Test
248     public void testDoubleGenerationMethods() {
249         final long allBits = 0xffffffffffffffffL;
250 
251         // Not capable of generating 1. Set the delta with 1 or 2 ULP of 1.
252         assertCloseToNotAbove1((allBits >>> 12) * 0x1.0p-52d, 2);
253         assertCloseToNotAbove1((allBits >>> 11) * 0x1.0p-53d, 1);
254         assertCloseToNotAbove1(Double.longBitsToDouble(0x3ffL << 52 | allBits >>> 12) - 1.0, 2);
255 
256         final long noBits = 0;
257         Assert.assertEquals(0.0, (noBits >>> 12) * 0x1.0p-52d, 0);
258         Assert.assertEquals(0.0, (noBits >>> 11) * 0x1.0p-53d, 0);
259         Assert.assertEquals(0.0, Double.longBitsToDouble(0x3ffL << 52 | noBits >>> 12) - 1.0, 0);
260     }
261 
262     @Test
263     public void testMakeDoubleFromLong() {
264         final long allBits = 0xffffffffffffffffL;
265         final long noBits = 0;
266         // Within 1 ULP of 1.0
267         assertCloseToNotAbove1(NumberFactory.makeDouble(allBits), 1);
268         Assert.assertEquals(0.0, NumberFactory.makeDouble(noBits), 0);
269     }
270 
271     @Test
272     public void testMakeDoubleFromIntInt() {
273         final int allBits = 0xffffffff;
274         final int noBits = 0;
275         // Within 1 ULP of 1.0
276         assertCloseToNotAbove1(NumberFactory.makeDouble(allBits, allBits), 1);
277         Assert.assertEquals(0.0, NumberFactory.makeDouble(noBits, noBits), 0);
278     }
279 
280     @Test
281     public void testMakeFloatFromInt() {
282         final int allBits = 0xffffffff;
283         final int noBits = 0;
284         // Within 1 ULP of 1.0f
285         assertCloseToNotAbove1(NumberFactory.makeFloat(allBits), 1);
286         Assert.assertEquals(0.0f, NumberFactory.makeFloat(noBits), 0);
287     }
288 
289     /**
290      * Assert that the value is close to but <strong>not above</strong> 1. This is used to test
291      * the output from methods that produce a {@code float} value that must be in the range
292      * between 0 and 1.
293      *
294      * @param value the value
295      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point values between x and y.
296      * @see Precision#equals(float, float, int)
297      */
298     private static void assertCloseToNotAbove1(float value, int maxUlps) {
299         Assert.assertTrue("Not <= 1.0f", value <= 1.0f);
300         Assert.assertTrue("Not equal to 1.0f within units of least precision: " + maxUlps,
301                           Precision.equals(1.0f, value, maxUlps));
302     }
303 
304     /**
305      * Assert that the value is close to but <strong>not above</strong> 1. This is used to test
306      * the output from methods that produce a {@code double} value that must be in the range
307      * between 0 and 1.
308      *
309      * @param value the value
310      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point values between x and y.
311      * @see Precision#equals(double, double, int)
312      */
313     private static void assertCloseToNotAbove1(double value, int maxUlps) {
314         Assert.assertTrue("Not <= 1.0", value <= 1.0);
315         Assert.assertTrue("Not equal to 1.0 within units of least precision: " + maxUlps,
316                           Precision.equals(1.0, value, maxUlps));
317     }
318 }