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 }