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