diff --git a/base/random.jl b/base/random.jl index 2353f2bd50e98..169af1810ada0 100644 --- a/base/random.jl +++ b/base/random.jl @@ -361,7 +361,9 @@ maxmultiple(k::UInt128) = div(typemax(UInt128), k + (k == 0))*k - 1 # maximum multiple of k within 1:2^32 or 1:2^64, depending on size maxmultiplemix(k::UInt64) = (div((k >> 32 != 0)*0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000, k + (k == 0))*k - 1) % UInt64 -immutable RandIntGen{T<:Integer, U<:Unsigned} +abstract RangeGenerator + +immutable RandIntGen{T<:Integer, U<:Unsigned} <: RangeGenerator a::T # first element of the range k::U # range length or zero for full range u::U # rejection threshold @@ -373,16 +375,36 @@ RandIntGen{T}(a::T, k::UInt64) = RandIntGen{T,UInt64}(a, k, maxmultiplemix(k)) # generator for ranges -RandIntGen{T<:Unsigned}(r::UnitRange{T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), last(r) - first(r) + one(T)) +inrange{T<:Unsigned}(r::UnitRange{T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), last(r) - first(r) + one(T)) # specialized versions for (T, U) in [(UInt8, UInt32), (UInt16, UInt32), (Int8, UInt32), (Int16, UInt32), (Int32, UInt32), (Int64, UInt64), (Int128, UInt128), (Bool, UInt32)] - @eval RandIntGen(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, unsigned(last(r) - first(r)) + one($U))) # overflow ok + @eval inrange(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, unsigned(last(r) - first(r)) + one($U))) # overflow ok +end + + +# generator for BigInt +immutable RandIntGenBigInt <: RangeGenerator + a::BigInt # first + m::BigInt # range length - 1 + limbs::Array{Culong} # buffer to be copied into generated BigInt's + mask::Culong # applied to the highest limb end +function inrange(r::UnitRange{BigInt}) + m = last(r) - first(r) + m < 0 && error("range must be non-empty") + nd = ndigits(m, 2) + nlimbs, highbits = divrem(nd, 8*sizeof(Culong)) + highbits > 0 && (nlimbs += 1) + mask = highbits == 0 ? ~zero(Culong) : one(Culong)<