Alex Herbert created RNG-172:
--------------------------------
Summary: UniformLongSampler can precompute the rejection limit
Key: RNG-172
URL: https://issues.apache.org/jira/browse/RNG-172
Project: Commons RNG
Issue Type: Improvement
Components: sampling
Affects Versions: 1.4
Reporter: Alex Herbert
Fix For: 1.5
The UniformLongSampler uses this rejection algorithm for non-powers of 2 range
'n':
{code:java}
@Override
public long sample() {
// Rejection algorithm copied from o.a.c.rng.core.BaseProvider
// to avoid the (n <= 0) conditional.
// See the JDK javadoc for java.util.Random.nextInt(int) for
// a description of the algorithm.
long bits;
long val;
do {
bits = rng.nextLong() >>> 1;
val = bits % n;
} while (bits - val + (n - 1) < 0);
return val;
}
{code}
This requires a modulus operation per iteration. Worst case expected iteration
of the loop is 2 times and thus 2 modulus calls.
However the statement {{while (bits - val + (n - 1) < 0)}} is checking if the
bits came from the range [0, limit) where limit is the largest multiple of n
that is a positive value. Essential the bits must uniformly be picked from a
range that can be used with modulus n and still be uniform for all values.
This limit can be precomputed and the sampling loop changed to have 1 modulus
call:
{code:java}
@Override
public long sample() {
// Note:
// This will have the same output as the rejection algorithm
// from o.a.c.rng.core.BaseProvider. The limit for the uniform
// positive value can be pre-computed. This ensures exactly
// 1 modulus operation per call.
long bits = rng.nextLong() >>> 1;
while (bits >= limit) {
bits = rng.nextLong() >>> 1;
}
return bits % n;
}
{code}
This does not work if the range n is a power of 2 as the limit is 2^63 and no
sample for bits can be above it. This sampler uses a different method for power
of 2 range and so the limit can be precomputed as used here.
The output from the sampler will be the same.
--
This message was sent by Atlassian Jira
(v8.20.1#820001)