Skip to content

Commit

Permalink
sometimes faster rand(::Xoshiro, ::UnitRange{Int128}) (JuliaLang#41067
Browse files Browse the repository at this point in the history
)
  • Loading branch information
rfourquet committed Jun 10, 2021
1 parent 7d2e640 commit ecab430
Showing 1 changed file with 23 additions and 11 deletions.
34 changes: 23 additions & 11 deletions stdlib/Random/src/generation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ end

### BitInteger

# there are three implemented samplers for unit ranges, the two first of which
# assume that Float64 (i.e. 52 random bits) is the native type for the RNG:
# 1) "Fast" (SamplerRangeFast), which is most efficient when the underlying RNG produces
# rand(Float64) "fast enough".
# there are three implemented samplers for unit ranges, the second one
# assumes that Float64 (i.e. 52 random bits) is the native type for the RNG:
# 1) "Fast" (SamplerRangeFast), which is most efficient when the range length is close
# (or equal) to a power of 2 from below.
# The tradeoff is faster creation of the sampler, but more consumption of entropy bits.
# 2) "Slow" (SamplerRangeInt) which tries to use as few entropy bits as possible, at the
# cost of a bigger upfront price associated with the creation of the sampler.
Expand Down Expand Up @@ -224,20 +224,32 @@ function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt32,T}) where T
(x + a % UInt32) % T
end

has_fast_64(rng::AbstractRNG) = rng_native_52(rng) != Float64
# for MersenneTwister, both options have very similar performance

function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt64,T}) where T
a, bw, m, mask = sp.a, sp.bw, sp.m, sp.mask
x = bw <= 52 ? rand(rng, LessThan(m, Masked(mask, UInt52Raw()))) :
rand(rng, LessThan(m, Masked(mask, uniform(UInt64))))
if !has_fast_64(rng) && bw <= 52
x = rand(rng, LessThan(m, Masked(mask, UInt52Raw())))
else
x = rand(rng, LessThan(m, Masked(mask, uniform(UInt64))))
end
(x + a % UInt64) % T
end

function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt128,T}) where T
a, bw, m, mask = sp.a, sp.bw, sp.m, sp.mask
x = bw <= 52 ?
rand(rng, LessThan(m % UInt64, Masked(mask % UInt64, UInt52Raw()))) % UInt128 :
bw <= 104 ?
rand(rng, LessThan(m, Masked(mask, UInt104Raw()))) :
rand(rng, LessThan(m, Masked(mask, uniform(UInt128))))
if has_fast_64(rng)
x = bw <= 64 ?
rand(rng, LessThan(m % UInt64, Masked(mask % UInt64, uniform(UInt64)))) % UInt128 :
rand(rng, LessThan(m, Masked(mask, uniform(UInt128))))
else
x = bw <= 52 ?
rand(rng, LessThan(m % UInt64, Masked(mask % UInt64, UInt52Raw()))) % UInt128 :
bw <= 104 ?
rand(rng, LessThan(m, Masked(mask, UInt104Raw()))) :
rand(rng, LessThan(m, Masked(mask, uniform(UInt128))))
end
x % T + a
end

Expand Down

0 comments on commit ecab430

Please sign in to comment.