[ 
https://issues.apache.org/jira/browse/RNG-172?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Alex Herbert resolved RNG-172.
------------------------------
    Resolution: Implemented

Updated in commit:

994616fa38039c295535f24b5242bf0a7f5b0ead

> 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
>            Priority: Trivial
>             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)

Reply via email to