blob: a82a393153848a9d1a3dad9b992b102e89b03bb0 [file] [log] [blame]
/*
* 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.examples.stress;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.core.source32.IntProvider;
import java.util.concurrent.ThreadLocalRandom;
/**
* Utility methods for a {@link UniformRandomProvider}.
*/
final class RNGUtils {
/**
* Used to build 4-bit numbers as Hex.
*/
private static final char[] HEX_DIGITS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
/** No public construction. */
private RNGUtils() {}
/**
* Wrap the random generator with an {@link IntProvider} that will reverse the byte order
* of the {@code int}.
*
* @param rng The random generator.
* @return the byte reversed random generator.
* @see Integer#reverseBytes(int)
*/
static UniformRandomProvider createReverseBytesIntProvider(final UniformRandomProvider rng) {
// Note:
// This always uses an IntProvider even if the underlying RNG is a LongProvider.
// A LongProvider will produce 2 ints from 8 bytes of a long: 76543210 -> 7654 3210.
// This will be reversed to output 2 ints as: 4567 0123.
// This is a different output order than if reversing the entire long: 0123 4567.
// The effect is to output the most significant bits from the long first, and
// the least significant bits second. Thus the output of ints will be the same
// on big-endian and little-endian platforms.
return new IntProvider() {
@Override
public int next() {
return Integer.reverseBytes(rng.nextInt());
}
@Override
public String toString() {
return "Byte-reversed " + rng.toString();
}
};
}
/**
* Wrap the random generator with an {@link IntProvider} that will reverse the bits
* of the {@code int}.
*
* @param rng The random generator.
* @return the bit reversed random generator.
* @see Integer#reverse(int)
*/
static UniformRandomProvider createReverseBitsIntProvider(final UniformRandomProvider rng) {
return new IntProvider() {
@Override
public int next() {
return Integer.reverse(rng.nextInt());
}
@Override
public String toString() {
return "Bit-reversed " + rng.toString();
}
};
}
/**
* Wrap the random generator with an {@link IntProvider} that will combine the bits
* using a {@code xor} operation with a generated hash code.
*
* <pre>{@code
* System.identityHashCode(new Object()) ^ rng.nextInt()
* }</pre>
*
* Note: This generator will be slow.
*
* @param rng The random generator.
* @return the combined random generator.
* @see System#identityHashCode(Object)
*/
static UniformRandomProvider createHashCodeIntProvider(final UniformRandomProvider rng) {
return new IntProvider() {
@Override
public int next() {
return System.identityHashCode(new Object()) ^ rng.nextInt();
}
@Override
public String toString() {
return "HashCode ^ " + rng.toString();
}
};
}
/**
* Wrap the random generator with an {@link IntProvider} that will combine the bits
* using a {@code xor} operation with the output from {@link ThreadLocalRandom}.
*
* <pre>{@code
* ThreadLocalRandom.current().nextInt() ^ rng.nextInt()
* }</pre>
*
* @param rng The random generator.
* @return the combined random generator.
*/
static UniformRandomProvider createThreadLocalRandomIntProvider(final UniformRandomProvider rng) {
return new IntProvider() {
@Override
public int next() {
return ThreadLocalRandom.current().nextInt() ^ rng.nextInt();
}
@Override
public String toString() {
return "ThreadLocalRandom ^ " + rng.toString();
}
};
}
/**
* Combine the two random generators using a {@code xor} operations.
*
* <pre>{@code
* rng1.nextInt() ^ rng2.nextInt()
* }</pre>
*
* @param rng1 The first random generator.
* @param rng2 The second random generator.
* @return the combined random generator.
*/
static UniformRandomProvider createXorIntProvider(final UniformRandomProvider rng1,
final UniformRandomProvider rng2) {
return new IntProvider() {
@Override
public int next() {
return rng1.nextInt() ^ rng2.nextInt();
}
@Override
public String toString() {
return rng1.toString() + " ^ " + rng2.toString();
}
};
}
/**
* Parses the argument into an object suitable for the RandomSource constructor. Supports:
*
* <ul>
* <li>Integer
* </ul>
*
* @param argument the argument
* @return the object
* @throws ApplicationException If the argument is not recognised
*/
static Object parseArgument(String argument) {
try {
// Currently just support TWO_CMRES_SELECT which uses integers.
// Future RandomSource implementations may require other parsing, for example
// recognising a long by the suffix 'L'. This functionality
// could use Commons Lang NumberUtils.createNumber(String).
return Integer.parseInt(argument);
} catch (final NumberFormatException ex) {
throw new ApplicationException("Failed to parse RandomSource argument: " + argument, ex);
}
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal
* values of each byte in order. The returned array will be double the length of the
* passed array, as it takes two characters to represent any given byte.
*
* <p>This can be used to encode byte array seeds into a text representation.</p>
*
* <p>Adapted from commons-codec.</p>
*
* @param data a byte[] to convert to Hex characters
* @return A char[] containing the lower-case Hex representation
*/
static char[] encodeHex(final byte[] data) {
final int l = data.length;
final char[] out = new char[l << 1];
// Two characters form the hex value
for (int i = 0; i < l; i++) {
// Upper 4-bits
out[2 * i] = HEX_DIGITS[(0xf0 & data[i]) >>> 4];
// Lower 4-bits
out[2 * i + 1] = HEX_DIGITS[ 0x0f & data[i]];
}
return out;
}
}