@@ -166,13 +166,15 @@ end
166
166
167
167
# ## BitInteger
168
168
169
- # there are two implemented samplers for unit ranges, which assume that Float64 (i.e.
170
- # 52 random bits) is the native type for the RNG:
171
- # 1) "Fast", which is the most efficient when the underlying RNG produces rand(Float64)
172
- # "fast enough". The tradeoff is faster creation of the sampler, but more
173
- # consumption of entropy bits
169
+ # there are three implemented samplers for unit ranges, the two first of which
170
+ # assume that Float64 (i.e. 52 random bits) is the native type for the RNG:
171
+ # 1) "Fast", which is most efficient when the underlying RNG produces rand(Float64)
172
+ # "fast enough". The tradeoff is faster creation of the sampler, but more
173
+ # consumption of entropy bits
174
174
# 2) "Default" which tries to use as few entropy bits as possible, at the cost of a
175
175
# a bigger upfront price associated with the creation of the sampler
176
+ # 3) "Nearly Division Less", which is the fastest algorithm for types of size
177
+ # up to 64 bits. This will be the default in a future realease.
176
178
177
179
# ### helper functions
178
180
@@ -295,6 +297,45 @@ function rand(rng::AbstractRNG, sp::SamplerRangeInt{T,UInt128}) where T<:BitInte
295
297
return ((sp. a % UInt128) + rem_knuth (x, sp. k)) % T
296
298
end
297
299
300
+ # ### Nearly Division Less
301
+
302
+ # cf. https://arxiv.org/abs/1805.10941
303
+
304
+ struct SamplerRangeNDL{U<: Unsigned ,T} <: Sampler{T}
305
+ a:: T # first element of the range
306
+ s:: U # range length or zero for full range
307
+ end
308
+
309
+ function SamplerRangeNDL (r:: AbstractUnitRange{T} ) where {T}
310
+ isempty (r) && throw (ArgumentError (" range must be non-empty" ))
311
+ a = first (r)
312
+ U = uint_sup (T)
313
+ s = (last (r) - first (r)) % unsigned (T) % U + one (U) # overflow ok
314
+ # mod(-s, s) could be put in the Sampler object for repeated calls, but
315
+ # this would be an advantage only for very big s and number of calls
316
+ SamplerRangeNDL (a, s)
317
+ end
318
+
319
+ function rand (rng:: AbstractRNG , sp:: SamplerRangeNDL{U,T} ) where {U,T}
320
+ s = sp. s
321
+ x = widen (rand (rng, U))
322
+ m = x * s
323
+ l = m % U
324
+ if l < s
325
+ t = mod (- s, s)
326
+ while l < t
327
+ x = widen (rand (rng, U))
328
+ m = x * s
329
+ l = m % U
330
+ end
331
+ end
332
+ (s == 0 ? x : m >> (8 * sizeof (U))) % T + sp. a
333
+ end
334
+
335
+ # API until this is made the default
336
+ fast (r:: AbstractUnitRange{<:Base.BitInteger64} ) = SamplerRangeNDL (r)
337
+ fast (r:: AbstractArray ) = Random. SamplerSimple (r, fast (firstindex (r): lastindex (r)))
338
+
298
339
299
340
# ## BigInt
300
341
0 commit comments