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 java.util.Arrays;
20  
21  /**
22   * Utility for creating number types from one or two {@code int} values
23   * or one {@code long} value, or a sequence of bytes.
24   */
25  public final class NumberFactory {
26      /** See {@link #makeDouble(long)}. */
27      private static final long DOUBLE_HIGH_BITS = 0x3ffL << 52;
28      /** See {@link #makeFloat(int)}. */
29      private static final float FLOAT_MULTIPLIER = 0x1.0p-23f;
30      /** See {@link #makeDouble(int, int)}. */
31      private static final double DOUBLE_MULTIPLIER = 0x1.0p-52d;
32      /** Lowest byte mask. */
33      private static final long LONG_LOWEST_BYTE_MASK = 0xffL;
34      /** Number of bytes in a {@code long}. */
35      private static final int LONG_SIZE = 8;
36      /** Lowest byte mask. */
37      private static final int INT_LOWEST_BYTE_MASK = 0xff;
38      /** Number of bytes in a {@code int}. */
39      private static final int INT_SIZE = 4;
40  
41      /**
42       * Class contains only static methods.
43       */
44      private NumberFactory() {}
45  
46      /**
47       * @param v Number.
48       * @return a boolean.
49       */
50      public static boolean makeBoolean(int v) {
51          return (v >>> 31) != 0;
52      }
53  
54      /**
55       * @param v Number.
56       * @return a boolean.
57       */
58      public static boolean makeBoolean(long v) {
59          return (v >>> 63) != 0;
60      }
61  
62      /**
63       * @param v Number.
64       * @return a {@code double} value in the interval {@code [0, 1]}.
65       */
66      public static double makeDouble(long v) {
67          // http://xorshift.di.unimi.it
68          return Double.longBitsToDouble(DOUBLE_HIGH_BITS | v >>> 12) - 1d;
69      }
70  
71      /**
72       * @param v Number (high order bits).
73       * @param w Number (low order bits).
74       * @return a {@code double} value in the interval {@code [0, 1]}.
75       */
76      public static double makeDouble(int v,
77                                      int w) {
78          final long high = ((long) (v >>> 6)) << 26;
79          final int low = w >>> 6;
80          return (high | low) * DOUBLE_MULTIPLIER;
81      }
82  
83      /**
84       * @param v Number.
85       * @return a {@code float} value in the interval {@code [0, 1]}.
86       */
87      public static float makeFloat(int v) {
88          return (v >>> 9) * FLOAT_MULTIPLIER;
89      }
90  
91      /**
92       * @param v Number (high order bits).
93       * @param w Number (low order bits).
94       * @return a {@code long} value.
95       */
96      public static long makeLong(int v,
97                                  int w) {
98          return (((long) v) << 32) | (w & 0xffffffffL);
99      }
100 
101     /**
102      * Creates an {@code int} from a {@code long}.
103      *
104      * @param v Number.
105      * @return an {@code int} value made from the "xor" of the
106      * {@link #extractHi(long) high order bits} and
107      * {@link #extractLo(long) low order bits} of {@code v}.
108      */
109     public static int makeInt(long v) {
110         return extractHi(v) ^ extractLo(v);
111     }
112 
113     /**
114      * Creates an {@code int} from a {@code long}, using the high order bits.
115      *
116      * <p>The returned value is such that if</p>
117      * <pre><code>
118      *  vL = extractLo(v);
119      *  vH = extractHi(v);
120      * </code></pre>
121      *
122      * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p>
123      *
124      * @param v Number.
125      * @return an {@code int} value made from the most significant bits
126      * of {@code v}.
127      */
128     public static int extractHi(long v) {
129         return (int) (v >>> 32);
130     }
131 
132     /**
133      * Creates an {@code int} from a {@code long}, using the low order bits.
134      *
135      * <p>The returned value is such that if</p>
136      *
137      * <pre><code>
138      *  vL = extractLo(v);
139      *  vH = extractHi(v);
140      * </code></pre>
141      *
142      * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p>
143      *
144      * @param v Number.
145      * @return an {@code int} value made from the least significant bits
146      * of {@code v}.
147      */
148     public static int extractLo(long v) {
149         return (int) v;
150     }
151 
152     /**
153      * Splits a {@code long} into 8 bytes.
154      *
155      * @param v Value.
156      * @return the bytes that compose the given value (least-significant
157      * byte first).
158      */
159     public static byte[] makeByteArray(long v) {
160         final byte[] b = new byte[LONG_SIZE];
161 
162         for (int i = 0; i < LONG_SIZE; i++) {
163             final int shift = i * 8;
164             b[i] = (byte) ((v >>> shift) & LONG_LOWEST_BYTE_MASK);
165         }
166 
167         return b;
168     }
169 
170     /**
171      * Creates a {@code long} from 8 bytes.
172      *
173      * @param input Input.
174      * @return the value that correspond to the given bytes assuming
175      * that the is ordered in increasing byte significance (i.e. the
176      * first byte in the array is the least-siginficant).
177      * @throws IllegalArgumentException if {@code input.length != 8}.
178      */
179     public static long makeLong(byte[] input) {
180         checkSize(LONG_SIZE, input.length);
181 
182         long v = 0;
183         for (int i = 0; i < LONG_SIZE; i++) {
184             final int shift = i * 8;
185             v |= (((long) input[i]) & LONG_LOWEST_BYTE_MASK) << shift;
186         }
187 
188         return v;
189     }
190 
191     /**
192      * Splits an array of {@code long} values into a sequence of bytes.
193      * This method calls {@link #makeByteArray(long)} for each element of
194      * the {@code input}.
195      *
196      * @param input Input.
197      * @return an array of bytes.
198      */
199     public static byte[] makeByteArray(long[] input) {
200         final int size = input.length * LONG_SIZE;
201         final byte[] b = new byte[size];
202 
203         for (int i = 0; i < input.length; i++) {
204             final byte[] current = makeByteArray(input[i]);
205             System.arraycopy(current, 0, b, i * LONG_SIZE, LONG_SIZE);
206         }
207 
208         return b;
209     }
210 
211     /**
212      * Creates an array of {@code long} values from a sequence of bytes.
213      * This method calls {@link #makeLong(byte[])} for each subsequence
214      * of 8 bytes.
215      *
216      * @param input Input.
217      * @return an array of {@code long}.
218      * @throws IllegalArgumentException if {@code input.length} is not
219      * a multiple of 8.
220      */
221     public static long[] makeLongArray(byte[] input) {
222         final int size = input.length;
223         final int num = size / LONG_SIZE;
224         checkSize(num * LONG_SIZE, size);
225 
226         final long[] output = new long[num];
227         for (int i = 0; i < num; i++) {
228             final int from = i * LONG_SIZE;
229             final byte[] current = Arrays.copyOfRange(input, from, from + LONG_SIZE);
230             output[i] = makeLong(current);
231         }
232 
233         return output;
234     }
235 
236     /**
237      * Splits an {@code int} into 4 bytes.
238      *
239      * @param v Value.
240      * @return the bytes that compose the given value (least-significant
241      * byte first).
242      */
243     public static byte[] makeByteArray(int v) {
244         final byte[] b = new byte[INT_SIZE];
245 
246         for (int i = 0; i < INT_SIZE; i++) {
247             final int shift = i * 8;
248             b[i] = (byte) ((v >>> shift) & INT_LOWEST_BYTE_MASK);
249         }
250 
251         return b;
252     }
253 
254     /**
255      * Creates an {@code int} from 4 bytes.
256      *
257      * @param input Input.
258      * @return the value that correspond to the given bytes assuming
259      * that the is ordered in increasing byte significance (i.e. the
260      * first byte in the array is the least-siginficant).
261      * @throws IllegalArgumentException if {@code input.length != 4}.
262      */
263     public static int makeInt(byte[] input) {
264         checkSize(INT_SIZE, input.length);
265 
266         int v = 0;
267         for (int i = 0; i < INT_SIZE; i++) {
268             final int shift = i * 8;
269             v |= (((int) input[i]) & INT_LOWEST_BYTE_MASK) << shift;
270         }
271 
272         return v;
273     }
274 
275     /**
276      * Splits an array of {@code int} values into a sequence of bytes.
277      * This method calls {@link #makeByteArray(int)} for each element of
278      * the {@code input}.
279      *
280      * @param input Input.
281      * @return an array of bytes.
282      */
283     public static byte[] makeByteArray(int[] input) {
284         final int size = input.length * INT_SIZE;
285         final byte[] b = new byte[size];
286 
287         for (int i = 0; i < input.length; i++) {
288             final byte[] current = makeByteArray(input[i]);
289             System.arraycopy(current, 0, b, i * INT_SIZE, INT_SIZE);
290         }
291 
292         return b;
293     }
294 
295     /**
296      * Creates an array of {@code int} values from a sequence of bytes.
297      * This method calls {@link #makeInt(byte[])} for each subsequence
298      * of 4 bytes.
299      *
300      * @param input Input. Length must be a multiple of 4.
301      * @return an array of {@code int}.
302      * @throws IllegalArgumentException if {@code input.length} is not
303      * a multiple of 4.
304      */
305     public static int[] makeIntArray(byte[] input) {
306         final int size = input.length;
307         final int num = size / INT_SIZE;
308         checkSize(num * INT_SIZE, size);
309 
310         final int[] output = new int[num];
311         for (int i = 0; i < num; i++) {
312             final int from = i * INT_SIZE;
313             final byte[] current = Arrays.copyOfRange(input, from, from + INT_SIZE);
314             output[i] = makeInt(current);
315         }
316 
317         return output;
318     }
319 
320     /**
321      * @param expected Expected value.
322      * @param actual Actual value.
323      * @throw IllegalArgumentException if {@code expected != actual}.
324      */
325     private static void checkSize(int expected,
326                                   int actual) {
327         if (expected != actual) {
328             throw new IllegalArgumentException("Array size: Expected " + expected +
329                                                " but was " + actual);
330         }
331     }
332 }