in commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/FastLoadedDiceRollerDiscreteSampler.java [493:544]
private static void convertToIntegers(double[] weights, long[] values, int[] exponents, int alpha) {
int maxExponent = Integer.MIN_VALUE;
for (int i = 0; i < weights.length; i++) {
final double weight = weights[i];
// Ignore zero.
// When creating the integer value later using bit shifts the result will remain zero.
if (weight == 0) {
continue;
}
final long bits = Double.doubleToRawLongBits(weight);
// For the IEEE 754 format see Double.longBitsToDouble(long).
// Extract the exponent (with the sign bit)
int exp = (int) (bits >>> MANTISSA_SIZE);
// Detect negative, infinite or NaN.
// Note: Negative values sign bit will cause the exponent to be too high.
if (exp > MAX_BIASED_EXPONENT) {
throw new IllegalArgumentException("Invalid weight: " + weight);
}
long mantissa;
if (exp == 0) {
// Sub-normal number:
mantissa = (bits & MANTISSA_MASK) << 1;
// Here we convert to a normalised number by counting the leading zeros
// to obtain the number of shifts of the most significant bit in
// the mantissa that is required to get a 1 at position 53 (i.e. as
// if it were a normal number with assumed leading bit).
final int shift = Long.numberOfLeadingZeros(mantissa << 11);
mantissa <<= shift;
exp -= shift;
} else {
// Normal number. Add the implicit leading 1-bit.
mantissa = (bits & MANTISSA_MASK) | (1L << MANTISSA_SIZE);
}
// Here the floating-point number is equal to:
// mantissa * 2^(exp-1075)
values[i] = mantissa;
exponents[i] = exp;
maxExponent = Math.max(maxExponent, exp);
}
// No exponent indicates that all weights are zero
if (maxExponent == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Sum of weights is zero");
}
filterWeights(values, exponents, alpha, maxExponent);
scaleWeights(values, exponents);
}