Skip to content
Permalink
Browse files
RNG-176: Remove redundant methods from core module
The methods are now present as default implementations in the client-api
UniformRandomProvider.

This requires JApiCmp is disabled as it does not recognise the change as
compatible. Binary compatibility is checked by revapi which allows this
change.
  • Loading branch information
aherbert committed May 13, 2022
1 parent d441d95 commit f3df9db1005142c24cb96ea0b9807282166d3718
Showing 4 changed files with 5 additions and 166 deletions.
@@ -26,10 +26,6 @@
*/
public abstract class BaseProvider
implements RestorableUniformRandomProvider {
/** Error message when an integer is not positive. */
private static final String NOT_POSITIVE = "Must be strictly positive: ";
/** 2^32. */
private static final long POW_32 = 1L << 32;
/**
* The fractional part of the the golden ratio, phi, scaled to 64-bits and rounded to odd.
* <pre>
@@ -41,45 +37,6 @@
/** The fractional part of the the golden ratio, phi, scaled to 32-bits and rounded to odd. */
private static final int GOLDEN_RATIO_32 = 0x9e3779b9;

/** {@inheritDoc} */
@Override
public int nextInt(int n) {
if (n <= 0) {
throw new IllegalArgumentException(NOT_POSITIVE + n);
}

// Lemire (2019): Fast Random Integer Generation in an Interval
// https://arxiv.org/abs/1805.10941
long m = (nextInt() & 0xffffffffL) * n;
long l = m & 0xffffffffL;
if (l < n) {
// 2^32 % n
final long t = POW_32 % n;
while (l < t) {
m = (nextInt() & 0xffffffffL) * n;
l = m & 0xffffffffL;
}
}
return (int) (m >>> 32);
}

/** {@inheritDoc} */
@Override
public long nextLong(long n) {
if (n <= 0) {
throw new IllegalArgumentException(NOT_POSITIVE + n);
}

long bits;
long val;
do {
bits = nextLong() >>> 1;
val = bits % n;
} while (bits - val + (n - 1) < 0);

return val;
}

/** {@inheritDoc} */
@Override
public RandomProviderState saveState() {
@@ -120,12 +120,6 @@ public double nextDouble() {
return NumberFactory.makeDouble(next(), next());
}

/** {@inheritDoc} */
@Override
public float nextFloat() {
return NumberFactory.makeFloat(next());
}

/** {@inheritDoc} */
@Override
public long nextLong() {
@@ -132,12 +132,6 @@ public int nextInt() {
return (int) bits;
}

/** {@inheritDoc} */
@Override
public double nextDouble() {
return NumberFactory.makeDouble(next());
}

/** {@inheritDoc} */
@Override
public boolean nextBoolean() {
@@ -153,115 +147,4 @@ public boolean nextBoolean() {
booleanSource = bits >>> 1;
return (bits & 0x1) == 1;
}

/** {@inheritDoc} */
@Override
public float nextFloat() {
return NumberFactory.makeFloat(nextInt());
}

/** {@inheritDoc} */
@Override
public void nextBytes(byte[] bytes) {
nextBytesFill(this, bytes, 0, bytes.length);
}

/** {@inheritDoc} */
@Override
public void nextBytes(byte[] bytes,
int start,
int len) {
checkFromIndexSize(start, len, bytes.length);
nextBytesFill(this, bytes, start, len);
}

/**
* Generates random bytes and places them into a user-supplied array.
*
* <p>
* The array is filled with bytes extracted from random {@code long} values.
* This implies that the number of random bytes generated may be larger than
* the length of the byte array.
* </p>
*
* @param source Source of randomness.
* @param bytes Array in which to put the generated bytes. Cannot be null.
* @param start Index at which to start inserting the generated bytes.
* @param len Number of bytes to insert.
*/
static void nextBytesFill(RandomLongSource source,
byte[] bytes,
int start,
int len) {
int index = start; // Index of first insertion.

// Index of first insertion plus multiple of 8 part of length
// (i.e. length with 3 least significant bits unset).
final int indexLoopLimit = index + (len & 0x7ffffff8);

// Start filling in the byte array, 8 bytes at a time.
while (index < indexLoopLimit) {
final long random = source.next();
bytes[index++] = (byte) random;
bytes[index++] = (byte) (random >>> 8);
bytes[index++] = (byte) (random >>> 16);
bytes[index++] = (byte) (random >>> 24);
bytes[index++] = (byte) (random >>> 32);
bytes[index++] = (byte) (random >>> 40);
bytes[index++] = (byte) (random >>> 48);
bytes[index++] = (byte) (random >>> 56);
}

final int indexLimit = start + len; // Index of last insertion + 1.

// Fill in the remaining bytes.
if (index < indexLimit) {
long random = source.next();
while (true) {
bytes[index++] = (byte) random;
if (index < indexLimit) {
random >>>= 8;
} else {
break;
}
}
}
}

/**
* Checks if the sub-range from fromIndex (inclusive) to fromIndex + size (exclusive) is
* within the bounds of range from 0 (inclusive) to length (exclusive).
*
* <p>This function provides the functionality of
* {@code java.utils.Objects.checkFromIndexSize} introduced in JDK 9. The
* <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html#checkFromIndexSize(int,int,int)">Objects</a>
* javadoc has been reproduced for reference.
*
* <p>The sub-range is defined to be out of bounds if any of the following inequalities
* is true:
* <ul>
* <li>{@code fromIndex < 0}
* <li>{@code size < 0}
* <li>{@code fromIndex + size > length}, taking into account integer overflow
* <li>{@code length < 0}, which is implied from the former inequalities
* </ul>
*
* @param fromIndex the lower-bound (inclusive) of the sub-interval
* @param size the size of the sub-range
* @param length the upper-bound (exclusive) of the range
* @return the fromIndex
* @throws IndexOutOfBoundsException if the sub-range is out of bounds
*/
private static int checkFromIndexSize(int fromIndex, int size, int length) {
// check for any negatives,
// or overflow safe length check given the values are all positive
// remaining = length - fromIndex
if ((fromIndex | size | length) < 0 || size > length - fromIndex) {
throw new IndexOutOfBoundsException(
// Note: %<d is 'relative indexing' to re-use the last argument
String.format("Range [%d, %<d + %d) out of bounds for length %d",
fromIndex, size, length));
}
return fromIndex;
}
}
@@ -15,3 +15,8 @@
# -----------------------------------------------------------------------------
#
# Empty file used to automatically trigger profile from commons parent pom
#
# TODO: Enable JApiCmp
# This has been disabled for the 1.4 to 1.5 comparison.
# JApiCmp does not recognise methods moved from a class to a default
# implementation in an interface.

0 comments on commit f3df9db

Please sign in to comment.