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 /** 20 * Utility for creating number types from one or two {@code int} values 21 * or one {@code long} value, or a sequence of bytes. 22 */ 23 public final class NumberFactory { 24 /** 25 * The multiplier to convert the least significant 24-bits of an {@code int} to a {@code float}. 26 * See {@link #makeFloat(int)}. 27 * 28 * <p>This is equivalent to 1.0f / (1 << 24). 29 */ 30 private static final float FLOAT_MULTIPLIER = 0x1.0p-24f; 31 /** 32 * The multiplier to convert the least significant 53-bits of a {@code long} to a {@code double}. 33 * See {@link #makeDouble(long)} and {@link #makeDouble(int, int)}. 34 * 35 * <p>This is equivalent to 1.0 / (1L << 53). 36 */ 37 private static final double DOUBLE_MULTIPLIER = 0x1.0p-53d; 38 /** Lowest byte mask. */ 39 private static final long LONG_LOWEST_BYTE_MASK = 0xffL; 40 /** Number of bytes in a {@code long}. */ 41 private static final int LONG_SIZE = 8; 42 /** Lowest byte mask. */ 43 private static final int INT_LOWEST_BYTE_MASK = 0xff; 44 /** Number of bytes in a {@code int}. */ 45 private static final int INT_SIZE = 4; 46 47 /** 48 * Class contains only static methods. 49 */ 50 private NumberFactory() {} 51 52 /** 53 * Creates a {@code boolean} from an {@code int} value. 54 * 55 * @param v Number. 56 * @return a boolean. 57 * 58 * @deprecated Since version 1.2. Method has become obsolete following 59 * <a href="https://issues.apache.org/jira/browse/RNG-57">RNG-57</a>. 60 */ 61 @Deprecated 62 public static boolean makeBoolean(int v) { 63 return v < 0; 64 } 65 66 /** 67 * Creates a {@code boolean} from a {@code long} value. 68 * 69 * @param v Number. 70 * @return a boolean. 71 * 72 * @deprecated Since version 1.2. Method has become obsolete following 73 * <a href="https://issues.apache.org/jira/browse/RNG-57">RNG-57</a>. 74 */ 75 @Deprecated 76 public static boolean makeBoolean(long v) { 77 return v < 0; 78 } 79 80 /** 81 * Creates a {@code double} from a {@code long} value. 82 * 83 * @param v Number. 84 * @return a {@code double} value in the interval {@code [0, 1]}. 85 */ 86 public static double makeDouble(long v) { 87 // Require the least significant 53-bits so shift the higher bits across 88 return (v >>> 11) * DOUBLE_MULTIPLIER; 89 } 90 91 /** 92 * Creates a {@code double} from two {@code int} values. 93 * 94 * @param v Number (high order bits). 95 * @param w Number (low order bits). 96 * @return a {@code double} value in the interval {@code [0, 1]}. 97 */ 98 public static double makeDouble(int v, 99 int w) { 100 // Require the least significant 53-bits from a long. 101 // Join the most significant 26 from v with 27 from w. 102 final long high = ((long) (v >>> 6)) << 27; // 26-bits remain 103 final int low = w >>> 5; // 27-bits remain 104 return (high | low) * DOUBLE_MULTIPLIER; 105 } 106 107 /** 108 * Creates a {@code float} from an {@code int} value. 109 * 110 * @param v Number. 111 * @return a {@code float} value in the interval {@code [0, 1]}. 112 */ 113 public static float makeFloat(int v) { 114 // Require the least significant 24-bits so shift the higher bits across 115 return (v >>> 8) * FLOAT_MULTIPLIER; 116 } 117 118 /** 119 * Creates a {@code long} from two {@code int} values. 120 * 121 * @param v Number (high order bits). 122 * @param w Number (low order bits). 123 * @return a {@code long} value. 124 */ 125 public static long makeLong(int v, 126 int w) { 127 return (((long) v) << 32) | (w & 0xffffffffL); 128 } 129 130 /** 131 * Creates an {@code int} from a {@code long}. 132 * 133 * @param v Number. 134 * @return an {@code int} value made from the "xor" of the 135 * {@link #extractHi(long) high order bits} and 136 * {@link #extractLo(long) low order bits} of {@code v}. 137 * 138 * @deprecated Since version 1.2. Method has become obsolete following 139 * <a href="https://issues.apache.org/jira/browse/RNG-57">RNG-57</a>. 140 */ 141 @Deprecated 142 public static int makeInt(long v) { 143 return extractHi(v) ^ extractLo(v); 144 } 145 146 /** 147 * Creates an {@code int} from a {@code long}, using the high order bits. 148 * 149 * <p>The returned value is such that if</p> 150 * <pre><code> 151 * vL = extractLo(v); 152 * vH = extractHi(v); 153 * </code></pre> 154 * 155 * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p> 156 * 157 * @param v Number. 158 * @return an {@code int} value made from the most significant bits 159 * of {@code v}. 160 */ 161 public static int extractHi(long v) { 162 return (int) (v >>> 32); 163 } 164 165 /** 166 * Creates an {@code int} from a {@code long}, using the low order bits. 167 * 168 * <p>The returned value is such that if</p> 169 * 170 * <pre><code> 171 * vL = extractLo(v); 172 * vH = extractHi(v); 173 * </code></pre> 174 * 175 * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p> 176 * 177 * @param v Number. 178 * @return an {@code int} value made from the least significant bits 179 * of {@code v}. 180 */ 181 public static int extractLo(long v) { 182 return (int) v; 183 } 184 185 /** 186 * Splits a {@code long} into 8 bytes. 187 * 188 * @param v Value. 189 * @return the bytes that compose the given value (least-significant 190 * byte first). 191 */ 192 public static byte[] makeByteArray(long v) { 193 final byte[] b = new byte[LONG_SIZE]; 194 putLong(v, b, 0); 195 return b; 196 } 197 198 /** 199 * Puts the {@code long} into the buffer starting at the given position. 200 * Adds 8 bytes (least-significant first). 201 * 202 * @param v Value. 203 * @param buffer the buffer. 204 * @param index the index. 205 */ 206 private static void putLong(long v, 207 byte[] buffer, 208 int index) { 209 buffer[index ] = (byte) (v & LONG_LOWEST_BYTE_MASK); 210 buffer[index + 1] = (byte)((v >>> 8) & LONG_LOWEST_BYTE_MASK); 211 buffer[index + 2] = (byte)((v >>> 16) & LONG_LOWEST_BYTE_MASK); 212 buffer[index + 3] = (byte)((v >>> 24) & LONG_LOWEST_BYTE_MASK); 213 buffer[index + 4] = (byte)((v >>> 32) & LONG_LOWEST_BYTE_MASK); 214 buffer[index + 5] = (byte)((v >>> 40) & LONG_LOWEST_BYTE_MASK); 215 buffer[index + 6] = (byte)((v >>> 48) & LONG_LOWEST_BYTE_MASK); 216 buffer[index + 7] = (byte) (v >>> 56); 217 } 218 219 /** 220 * Creates a {@code long} from 8 bytes. 221 * 222 * @param input Input. 223 * @return the value that correspond to the given bytes assuming 224 * that the order is in increasing byte significance (i.e. the 225 * first byte in the array is the least-significant). 226 * @throws IllegalArgumentException if {@code input.length != 8}. 227 */ 228 public static long makeLong(byte[] input) { 229 checkSize(LONG_SIZE, input.length); 230 return getLong(input, 0); 231 } 232 233 /** 234 * Gets the {@code long} from the buffer starting at the given position. 235 * Uses 8 bytes (least-significant first). 236 * 237 * @param input the input bytes. 238 * @param index the index. 239 * @return the value that correspond to the given bytes assuming 240 * that the order is in increasing byte significance (i.e. the 241 * first byte in the array is the least-significant). 242 */ 243 private static long getLong(byte[] input, 244 int index) { 245 return (input[index ] & LONG_LOWEST_BYTE_MASK) | 246 (input[index + 1] & LONG_LOWEST_BYTE_MASK) << 8 | 247 (input[index + 2] & LONG_LOWEST_BYTE_MASK) << 16 | 248 (input[index + 3] & LONG_LOWEST_BYTE_MASK) << 24 | 249 (input[index + 4] & LONG_LOWEST_BYTE_MASK) << 32 | 250 (input[index + 5] & LONG_LOWEST_BYTE_MASK) << 40 | 251 (input[index + 6] & LONG_LOWEST_BYTE_MASK) << 48 | 252 (input[index + 7] & LONG_LOWEST_BYTE_MASK) << 56; 253 } 254 255 /** 256 * Splits an array of {@code long} values into a sequence of bytes. 257 * This method calls {@link #makeByteArray(long)} for each element of 258 * the {@code input}. 259 * 260 * @param input Input. 261 * @return an array of bytes. 262 */ 263 public static byte[] makeByteArray(long[] input) { 264 final int size = input.length * LONG_SIZE; 265 final byte[] b = new byte[size]; 266 267 for (int i = 0; i < input.length; i++) { 268 putLong(input[i], b, i * LONG_SIZE); 269 } 270 271 return b; 272 } 273 274 /** 275 * Creates an array of {@code long} values from a sequence of bytes. 276 * This method calls {@link #makeLong(byte[])} for each subsequence 277 * of 8 bytes. 278 * 279 * @param input Input. 280 * @return an array of {@code long}. 281 * @throws IllegalArgumentException if {@code input.length} is not 282 * a multiple of 8. 283 */ 284 public static long[] makeLongArray(byte[] input) { 285 final int size = input.length; 286 final int num = size / LONG_SIZE; 287 checkSize(num * LONG_SIZE, size); 288 289 final long[] output = new long[num]; 290 for (int i = 0; i < num; i++) { 291 output[i] = getLong(input, i * LONG_SIZE); 292 } 293 294 return output; 295 } 296 297 /** 298 * Splits an {@code int} into 4 bytes. 299 * 300 * @param v Value. 301 * @return the bytes that compose the given value (least-significant 302 * byte first). 303 */ 304 public static byte[] makeByteArray(int v) { 305 final byte[] b = new byte[INT_SIZE]; 306 putInt(v, b, 0); 307 return b; 308 } 309 310 /** 311 * Puts the {@code int} into the buffer starting at the given position. 312 * Adds 4 bytes (least-significant first). 313 * 314 * @param v the value. 315 * @param buffer the buffer. 316 * @param index the index. 317 */ 318 private static void putInt(int v, 319 byte[] buffer, 320 int index) { 321 buffer[index ] = (byte) (v & INT_LOWEST_BYTE_MASK); 322 buffer[index + 1] = (byte)((v >>> 8) & INT_LOWEST_BYTE_MASK); 323 buffer[index + 2] = (byte)((v >>> 16) & INT_LOWEST_BYTE_MASK); 324 buffer[index + 3] = (byte) (v >>> 24); 325 } 326 /** 327 * Creates an {@code int} from 4 bytes. 328 * 329 * @param input Input. 330 * @return the value that correspond to the given bytes assuming 331 * that the order is in increasing byte significance (i.e. the 332 * first byte in the array is the least-significant). 333 * @throws IllegalArgumentException if {@code input.length != 4}. 334 */ 335 public static int makeInt(byte[] input) { 336 checkSize(INT_SIZE, input.length); 337 return getInt(input, 0); 338 } 339 340 /** 341 * Gets the {@code int} from the buffer starting at the given position. 342 * Uses 4 bytes (least-significant first). 343 * 344 * @param input the input bytes. 345 * @param index the index. 346 * @return the value that correspond to the given bytes assuming 347 * that the order is in increasing byte significance (i.e. the 348 * first byte in the array is the least-significant). 349 */ 350 private static int getInt(byte[] input, 351 int index) { 352 return (input[index ] & INT_LOWEST_BYTE_MASK) | 353 (input[index + 1] & INT_LOWEST_BYTE_MASK) << 8 | 354 (input[index + 2] & INT_LOWEST_BYTE_MASK) << 16 | 355 (input[index + 3] & INT_LOWEST_BYTE_MASK) << 24; 356 } 357 358 /** 359 * Splits an array of {@code int} values into a sequence of bytes. 360 * This method calls {@link #makeByteArray(int)} for each element of 361 * the {@code input}. 362 * 363 * @param input Input. 364 * @return an array of bytes. 365 */ 366 public static byte[] makeByteArray(int[] input) { 367 final int size = input.length * INT_SIZE; 368 final byte[] b = new byte[size]; 369 370 for (int i = 0; i < input.length; i++) { 371 putInt(input[i], b, i * INT_SIZE); 372 } 373 374 return b; 375 } 376 377 /** 378 * Creates an array of {@code int} values from a sequence of bytes. 379 * This method calls {@link #makeInt(byte[])} for each subsequence 380 * of 4 bytes. 381 * 382 * @param input Input. Length must be a multiple of 4. 383 * @return an array of {@code int}. 384 * @throws IllegalArgumentException if {@code input.length} is not 385 * a multiple of 4. 386 */ 387 public static int[] makeIntArray(byte[] input) { 388 final int size = input.length; 389 final int num = size / INT_SIZE; 390 checkSize(num * INT_SIZE, size); 391 392 final int[] output = new int[num]; 393 for (int i = 0; i < num; i++) { 394 output[i] = getInt(input, i * INT_SIZE); 395 } 396 397 return output; 398 } 399 400 /** 401 * @param expected Expected value. 402 * @param actual Actual value. 403 * @throws IllegalArgumentException if {@code expected != actual}. 404 */ 405 private static void checkSize(int expected, 406 int actual) { 407 if (expected != actual) { 408 throw new IllegalArgumentException("Array size: Expected " + expected + 409 " but was " + actual); 410 } 411 } 412 }