| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.rng.core.util; |
| |
| import java.util.Arrays; |
| |
| /** |
| * Utility for creating number types from one or two {@code int} values |
| * or one {@code long} value, or a sequence of bytes. |
| */ |
| public final class NumberFactory { |
| /** See {@link #makeDouble(long)}. */ |
| private static final long DOUBLE_HIGH_BITS = 0x3ffL << 52; |
| /** See {@link #makeFloat(int)}. */ |
| private static final float FLOAT_MULTIPLIER = 0x1.0p-23f; |
| /** See {@link #makeDouble(int, int)}. */ |
| private static final double DOUBLE_MULTIPLIER = 0x1.0p-52d; |
| /** Lowest byte mask. */ |
| private static final long LONG_LOWEST_BYTE_MASK = 0xffL; |
| /** Number of bytes in a {@code long}. */ |
| private static final int LONG_SIZE = 8; |
| /** Lowest byte mask. */ |
| private static final int INT_LOWEST_BYTE_MASK = 0xff; |
| /** Number of bytes in a {@code int}. */ |
| private static final int INT_SIZE = 4; |
| |
| /** |
| * Class contains only static methods. |
| */ |
| private NumberFactory() {} |
| |
| /** |
| * @param v Number. |
| * @return a boolean. |
| */ |
| public static boolean makeBoolean(int v) { |
| return (v >>> 31) != 0; |
| } |
| |
| /** |
| * @param v Number. |
| * @return a boolean. |
| */ |
| public static boolean makeBoolean(long v) { |
| return (v >>> 63) != 0; |
| } |
| |
| /** |
| * @param v Number. |
| * @return a {@code double} value in the interval {@code [0, 1]}. |
| */ |
| public static double makeDouble(long v) { |
| // http://xorshift.di.unimi.it |
| return Double.longBitsToDouble(DOUBLE_HIGH_BITS | v >>> 12) - 1d; |
| } |
| |
| /** |
| * @param v Number (high order bits). |
| * @param w Number (low order bits). |
| * @return a {@code double} value in the interval {@code [0, 1]}. |
| */ |
| public static double makeDouble(int v, |
| int w) { |
| final long high = ((long) (v >>> 6)) << 26; |
| final int low = w >>> 6; |
| return (high | low) * DOUBLE_MULTIPLIER; |
| } |
| |
| /** |
| * @param v Number. |
| * @return a {@code float} value in the interval {@code [0, 1]}. |
| */ |
| public static float makeFloat(int v) { |
| return (v >>> 9) * FLOAT_MULTIPLIER; |
| } |
| |
| /** |
| * @param v Number (high order bits). |
| * @param w Number (low order bits). |
| * @return a {@code long} value. |
| */ |
| public static long makeLong(int v, |
| int w) { |
| return (((long) v) << 32) | (w & 0xffffffffL); |
| } |
| |
| /** |
| * Creates an {@code int} from a {@code long}. |
| * |
| * @param v Number. |
| * @return an {@code int} value made from the "xor" of the |
| * {@link #extractHi(long) high order bits} and |
| * {@link #extractLo(long) low order bits} of {@code v}. |
| */ |
| public static int makeInt(long v) { |
| return extractHi(v) ^ extractLo(v); |
| } |
| |
| /** |
| * Creates an {@code int} from a {@code long}, using the high order bits. |
| * |
| * <p>The returned value is such that if</p> |
| * <pre><code> |
| * vL = extractLo(v); |
| * vH = extractHi(v); |
| * </code></pre> |
| * |
| * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p> |
| * |
| * @param v Number. |
| * @return an {@code int} value made from the most significant bits |
| * of {@code v}. |
| */ |
| public static int extractHi(long v) { |
| return (int) (v >>> 32); |
| } |
| |
| /** |
| * Creates an {@code int} from a {@code long}, using the low order bits. |
| * |
| * <p>The returned value is such that if</p> |
| * |
| * <pre><code> |
| * vL = extractLo(v); |
| * vH = extractHi(v); |
| * </code></pre> |
| * |
| * <p>then {@code v} is equal to {@link #makeLong(int,int) makeLong(vH, vL)}.</p> |
| * |
| * @param v Number. |
| * @return an {@code int} value made from the least significant bits |
| * of {@code v}. |
| */ |
| public static int extractLo(long v) { |
| return (int) v; |
| } |
| |
| /** |
| * Splits a {@code long} into 8 bytes. |
| * |
| * @param v Value. |
| * @return the bytes that compose the given value (least-significant |
| * byte first). |
| */ |
| public static byte[] makeByteArray(long v) { |
| final byte[] b = new byte[LONG_SIZE]; |
| |
| for (int i = 0; i < LONG_SIZE; i++) { |
| final int shift = i * 8; |
| b[i] = (byte) ((v >>> shift) & LONG_LOWEST_BYTE_MASK); |
| } |
| |
| return b; |
| } |
| |
| /** |
| * Creates a {@code long} from 8 bytes. |
| * |
| * @param input Input. |
| * @return the value that correspond to the given bytes assuming |
| * that the is ordered in increasing byte significance (i.e. the |
| * first byte in the array is the least-siginficant). |
| * @throws IllegalArgumentException if {@code input.length != 8}. |
| */ |
| public static long makeLong(byte[] input) { |
| checkSize(LONG_SIZE, input.length); |
| |
| long v = 0; |
| for (int i = 0; i < LONG_SIZE; i++) { |
| final int shift = i * 8; |
| v |= (((long) input[i]) & LONG_LOWEST_BYTE_MASK) << shift; |
| } |
| |
| return v; |
| } |
| |
| /** |
| * Splits an array of {@code long} values into a sequence of bytes. |
| * This method calls {@link #makeByteArray(long)} for each element of |
| * the {@code input}. |
| * |
| * @param input Input. |
| * @return an array of bytes. |
| */ |
| public static byte[] makeByteArray(long[] input) { |
| final int size = input.length * LONG_SIZE; |
| final byte[] b = new byte[size]; |
| |
| for (int i = 0; i < input.length; i++) { |
| final byte[] current = makeByteArray(input[i]); |
| System.arraycopy(current, 0, b, i * LONG_SIZE, LONG_SIZE); |
| } |
| |
| return b; |
| } |
| |
| /** |
| * Creates an array of {@code long} values from a sequence of bytes. |
| * This method calls {@link #makeLong(byte[])} for each subsequence |
| * of 8 bytes. |
| * |
| * @param input Input. |
| * @return an array of {@code long}. |
| * @throws IllegalArgumentException if {@code input.length} is not |
| * a multiple of 8. |
| */ |
| public static long[] makeLongArray(byte[] input) { |
| final int size = input.length; |
| final int num = size / LONG_SIZE; |
| checkSize(num * LONG_SIZE, size); |
| |
| final long[] output = new long[num]; |
| for (int i = 0; i < num; i++) { |
| final int from = i * LONG_SIZE; |
| final byte[] current = Arrays.copyOfRange(input, from, from + LONG_SIZE); |
| output[i] = makeLong(current); |
| } |
| |
| return output; |
| } |
| |
| /** |
| * Splits an {@code int} into 4 bytes. |
| * |
| * @param v Value. |
| * @return the bytes that compose the given value (least-significant |
| * byte first). |
| */ |
| public static byte[] makeByteArray(int v) { |
| final byte[] b = new byte[INT_SIZE]; |
| |
| for (int i = 0; i < INT_SIZE; i++) { |
| final int shift = i * 8; |
| b[i] = (byte) ((v >>> shift) & INT_LOWEST_BYTE_MASK); |
| } |
| |
| return b; |
| } |
| |
| /** |
| * Creates an {@code int} from 4 bytes. |
| * |
| * @param input Input. |
| * @return the value that correspond to the given bytes assuming |
| * that the is ordered in increasing byte significance (i.e. the |
| * first byte in the array is the least-siginficant). |
| * @throws IllegalArgumentException if {@code input.length != 4}. |
| */ |
| public static int makeInt(byte[] input) { |
| checkSize(INT_SIZE, input.length); |
| |
| int v = 0; |
| for (int i = 0; i < INT_SIZE; i++) { |
| final int shift = i * 8; |
| v |= (((int) input[i]) & INT_LOWEST_BYTE_MASK) << shift; |
| } |
| |
| return v; |
| } |
| |
| /** |
| * Splits an array of {@code int} values into a sequence of bytes. |
| * This method calls {@link #makeByteArray(int)} for each element of |
| * the {@code input}. |
| * |
| * @param input Input. |
| * @return an array of bytes. |
| */ |
| public static byte[] makeByteArray(int[] input) { |
| final int size = input.length * INT_SIZE; |
| final byte[] b = new byte[size]; |
| |
| for (int i = 0; i < input.length; i++) { |
| final byte[] current = makeByteArray(input[i]); |
| System.arraycopy(current, 0, b, i * INT_SIZE, INT_SIZE); |
| } |
| |
| return b; |
| } |
| |
| /** |
| * Creates an array of {@code int} values from a sequence of bytes. |
| * This method calls {@link #makeInt(byte[])} for each subsequence |
| * of 4 bytes. |
| * |
| * @param input Input. Length must be a multiple of 4. |
| * @return an array of {@code int}. |
| * @throws IllegalArgumentException if {@code input.length} is not |
| * a multiple of 4. |
| */ |
| public static int[] makeIntArray(byte[] input) { |
| final int size = input.length; |
| final int num = size / INT_SIZE; |
| checkSize(num * INT_SIZE, size); |
| |
| final int[] output = new int[num]; |
| for (int i = 0; i < num; i++) { |
| final int from = i * INT_SIZE; |
| final byte[] current = Arrays.copyOfRange(input, from, from + INT_SIZE); |
| output[i] = makeInt(current); |
| } |
| |
| return output; |
| } |
| |
| /** |
| * @param expected Expected value. |
| * @param actual Actual value. |
| * @throw IllegalArgumentException if {@code expected != actual}. |
| */ |
| private static void checkSize(int expected, |
| int actual) { |
| if (expected != actual) { |
| throw new IllegalArgumentException("Array size: Expected " + expected + |
| " but was " + actual); |
| } |
| } |
| } |