diff --git a/base/random/RNGs.jl b/base/random/RNGs.jl index e27a24b42c2d6..aa559c5f4a8ed 100644 --- a/base/random/RNGs.jl +++ b/base/random/RNGs.jl @@ -284,12 +284,12 @@ rng_native_52(::MersenneTwister) = Float64 #### helper functions # precondition: !mt_empty(r) -rand_inbounds(r::MersenneTwister, ::Close1Open2_64) = mt_pop!(r) -rand_inbounds(r::MersenneTwister, ::CloseOpen_64=CloseOpen()) = - rand_inbounds(r, Close1Open2()) - 1.0 +rand_inbounds(r::MersenneTwister, ::CloseOpen12_64) = mt_pop!(r) +rand_inbounds(r::MersenneTwister, ::CloseOpen01_64=CloseOpen01()) = + rand_inbounds(r, CloseOpen12()) - 1.0 rand_inbounds(r::MersenneTwister, ::UInt52Raw{T}) where {T<:BitInteger} = - reinterpret(UInt64, rand_inbounds(r, Close1Open2())) % T + reinterpret(UInt64, rand_inbounds(r, CloseOpen12())) % T function rand(r::MersenneTwister, x::SamplerTrivial{UInt52Raw{UInt64}}) reserve_1(r) @@ -308,7 +308,7 @@ end #### floats -rand(r::MersenneTwister, sp::SamplerTrivial{Close1Open2_64}) = +rand(r::MersenneTwister, sp::SamplerTrivial{CloseOpen12_64}) = (reserve_1(r); rand_inbounds(r, sp[])) #### integers @@ -377,7 +377,7 @@ function _rand_max383!(r::MersenneTwister, A::UnsafeView{Float64}, I::FloatInter @gc_preserve r unsafe_copyto!(A.ptr+m*sizeof(Float64), pointer(r.vals), n-m) r.idxF = n-m end - if I isa CloseOpen + if I isa CloseOpen01 for i=1:n A[i] -= 1.0 end @@ -386,10 +386,10 @@ function _rand_max383!(r::MersenneTwister, A::UnsafeView{Float64}, I::FloatInter end -fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::CloseOpen_64) = +fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::CloseOpen01_64) = dsfmt_fill_array_close_open!(s, A, n) -fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::Close1Open2_64) = +fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::CloseOpen12_64) = dsfmt_fill_array_close1_open2!(s, A, n) @@ -440,10 +440,10 @@ mask128(u::UInt128, ::Type{Float32}) = (u & 0x007fffff007fffff007fffff007fffff) | 0x3f8000003f8000003f8000003f800000 for T in (Float16, Float32) - @eval function rand!(r::MersenneTwister, A::Array{$T}, ::SamplerTrivial{Close1Open2{$T}}) + @eval function rand!(r::MersenneTwister, A::Array{$T}, ::SamplerTrivial{CloseOpen12{$T}}) n = length(A) n128 = n * sizeof($T) ÷ 16 - _rand!(r, A, 2*n128, Close1Open2()) + _rand!(r, A, 2*n128, CloseOpen12()) @gc_preserve A begin A128 = UnsafeView{UInt128}(pointer(A), n128) for i in 1:n128 @@ -468,8 +468,8 @@ for T in (Float16, Float32) A end - @eval function rand!(r::MersenneTwister, A::Array{$T}, ::SamplerTrivial{CloseOpen{$T}}) - rand!(r, A, Close1Open2($T)) + @eval function rand!(r::MersenneTwister, A::Array{$T}, ::SamplerTrivial{CloseOpen01{$T}}) + rand!(r, A, CloseOpen12($T)) I32 = one(Float32) for i in eachindex(A) @inbounds A[i] = Float32(A[i])-I32 # faster than "A[i] -= one(T)" for T==Float16 @@ -484,7 +484,7 @@ function rand!(r::MersenneTwister, A::UnsafeView{UInt128}, ::SamplerType{UInt128 n::Int=length(A) i = n while true - rand!(r, UnsafeView{Float64}(A.ptr, 2i), Close1Open2()) + rand!(r, UnsafeView{Float64}(A.ptr, 2i), CloseOpen12()) n < 5 && break i = 0 while n-i >= 5 diff --git a/base/random/generation.jl b/base/random/generation.jl index 363d09817699e..0d36a6a7c9f5b 100644 --- a/base/random/generation.jl +++ b/base/random/generation.jl @@ -17,29 +17,29 @@ ### random floats Sampler(rng::AbstractRNG, ::Type{T}, n::Repetition) where {T<:AbstractFloat} = - Sampler(rng, CloseOpen(T), n) + Sampler(rng, CloseOpen01(T), n) # generic random generation function which can be used by RNG implementors # it is not defined as a fallback rand method as this could create ambiguities -rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen{Float16}}) = +rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float16}}) = Float16(reinterpret(Float32, (rand(r, UInt10(UInt32)) << 13) | 0x3f800000) - 1) -rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen{Float32}}) = +rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float32}}) = reinterpret(Float32, rand(r, UInt23()) | 0x3f800000) - 1 -rand(r::AbstractRNG, ::SamplerTrivial{Close1Open2_64}) = +rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen12_64}) = reinterpret(Float64, 0x3ff0000000000000 | rand(r, UInt52())) -rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen_64}) = rand(r, Close1Open2()) - 1.0 +rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01_64}) = rand(r, CloseOpen12()) - 1.0 #### BigFloat const bits_in_Limb = sizeof(Limb) << 3 const Limb_high_bit = one(Limb) << (bits_in_Limb-1) -struct SamplerBigFloat{I<:FloatInterval{BigFloat}} <: Sampler +struct SamplerBigFloat{I<:FloatInterval{BigFloat}} <: Sampler{BigFloat} prec::Int nlimbs::Int limbs::Vector{Limb} @@ -70,13 +70,13 @@ function _rand(rng::AbstractRNG, sp::SamplerBigFloat) (z, randbool) end -function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::Close1Open2{BigFloat}) +function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::CloseOpen12{BigFloat}) z = _rand(rng, sp)[1] z.exp = 1 z end -function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::CloseOpen{BigFloat}) +function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::CloseOpen01{BigFloat}) z, randbool = _rand(rng, sp) z.exp = 0 randbool && @@ -88,8 +88,8 @@ end # alternative, with 1 bit less of precision # TODO: make an API for requesting full or not-full precision -function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::CloseOpen{BigFloat}, ::Nothing) - z = _rand(rng, sp, Close1Open2(BigFloat)) +function _rand(rng::AbstractRNG, sp::SamplerBigFloat, ::CloseOpen01{BigFloat}, ::Nothing) + z = _rand(rng, sp, CloseOpen12(BigFloat)) ccall((:mpfr_sub_ui, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, Int32), z, z, 1, Base.MPFR.ROUNDING_MODE[]) z @@ -108,7 +108,7 @@ rand(r::AbstractRNG, ::SamplerTrivial{UInt23Raw{UInt32}}) = rand(r, UInt32) rand(r::AbstractRNG, ::SamplerTrivial{UInt52Raw{UInt64}}) = _rand52(r, rng_native_52(r)) -_rand52(r::AbstractRNG, ::Type{Float64}) = reinterpret(UInt64, rand(r, Close1Open2())) +_rand52(r::AbstractRNG, ::Type{Float64}) = reinterpret(UInt64, rand(r, CloseOpen12())) _rand52(r::AbstractRNG, ::Type{UInt64}) = rand(r, UInt64) rand(r::AbstractRNG, ::SamplerTrivial{UInt104Raw{UInt128}}) = @@ -182,7 +182,7 @@ uint_sup(::Type{<:Union{Int128,UInt128}}) = UInt128 #### Fast -struct SamplerRangeFast{U<:BitUnsigned,T<:BitInteger} <: Sampler +struct SamplerRangeFast{U<:BitUnsigned,T<:BitInteger} <: Sampler{T} a::T # first element of the range bw::UInt # bit width m::U # range length - 1 @@ -243,7 +243,7 @@ maxmultiple(k::T, sup::T=zero(T)) where {T<:Unsigned} = unsafe_maxmultiple(k::T, sup::T) where {T<:Unsigned} = div(sup, k + (k == 0))*k - one(k) -struct SamplerRangeInt{T<:Integer,U<:Unsigned} <: Sampler +struct SamplerRangeInt{T<:Integer,U<:Unsigned} <: Sampler{T} a::T # first element of the range bw::Int # bit width k::U # range length or zero for full range @@ -298,7 +298,7 @@ end ### BigInt -struct SamplerBigInt <: Sampler +struct SamplerBigInt <: Sampler{BigInt} a::BigInt # first m::BigInt # range length - 1 nlimbs::Int # number of limbs in generated BigInt's (z ∈ [0, m]) @@ -364,9 +364,10 @@ end ## random values from Set -Sampler(rng::AbstractRNG, t::Set, n::Repetition) = SamplerTag{Set}(Sampler(rng, t.dict, n)) +Sampler(rng::AbstractRNG, t::Set{T}, n::Repetition) where {T} = + SamplerTag{Set{T}}(Sampler(rng, t.dict, n)) -rand(rng::AbstractRNG, sp::SamplerTag{Set,<:Sampler}) = rand(rng, sp.data).first +rand(rng::AbstractRNG, sp::SamplerTag{<:Set,<:Sampler}) = rand(rng, sp.data).first ## random values from BitSet diff --git a/base/random/random.jl b/base/random/random.jl index 2af2bcc31935c..a8d18aedf6c86 100644 --- a/base/random/random.jl +++ b/base/random/random.jl @@ -26,6 +26,7 @@ export srand, abstract type AbstractRNG end + ### integers # we define types which encode the generation of a specific number of bits @@ -67,15 +68,15 @@ end abstract type FloatInterval{T<:AbstractFloat} end -struct CloseOpen{ T<:AbstractFloat} <: FloatInterval{T} end # interval [0,1) -struct Close1Open2{T<:AbstractFloat} <: FloatInterval{T} end # interval [1,2) +struct CloseOpen01{T<:AbstractFloat} <: FloatInterval{T} end # interval [0,1) +struct CloseOpen12{T<:AbstractFloat} <: FloatInterval{T} end # interval [1,2) const FloatInterval_64 = FloatInterval{Float64} -const CloseOpen_64 = CloseOpen{Float64} -const Close1Open2_64 = Close1Open2{Float64} +const CloseOpen01_64 = CloseOpen01{Float64} +const CloseOpen12_64 = CloseOpen12{Float64} -CloseOpen( ::Type{T}=Float64) where {T<:AbstractFloat} = CloseOpen{T}() -Close1Open2(::Type{T}=Float64) where {T<:AbstractFloat} = Close1Open2{T}() +CloseOpen01(::Type{T}=Float64) where {T<:AbstractFloat} = CloseOpen01{T}() +CloseOpen12(::Type{T}=Float64) where {T<:AbstractFloat} = CloseOpen12{T}() Base.eltype(::Type{<:FloatInterval{T}}) where {T<:AbstractFloat} = T @@ -83,7 +84,9 @@ const BitFloatType = Union{Type{Float16},Type{Float32},Type{Float64}} ### Sampler -abstract type Sampler end +abstract type Sampler{E} end + +Base.eltype(::Sampler{E}) where {E} = E # temporarily for BaseBenchmarks RangeGenerator(x) = Sampler(GLOBAL_RNG, x) @@ -109,41 +112,48 @@ Sampler(rng::AbstractRNG, ::Type{X}) where {X} = Sampler(rng, X, Val(Inf)) #### pre-defined useful Sampler types # default fall-back for types -struct SamplerType{T} <: Sampler end +struct SamplerType{T} <: Sampler{T} end Sampler(::AbstractRNG, ::Type{T}, ::Repetition) where {T} = SamplerType{T}() -Base.getindex(sp::SamplerType{T}) where {T} = T +Base.getindex(::SamplerType{T}) where {T} = T # default fall-back for values -struct SamplerTrivial{T} <: Sampler +struct SamplerTrivial{T,E} <: Sampler{E} self::T end -Sampler(::AbstractRNG, X, ::Repetition) = SamplerTrivial(X) +SamplerTrivial(x::T) where {T} = SamplerTrivial{T,eltype(T)}(x) + +Sampler(::AbstractRNG, x, ::Repetition) = SamplerTrivial(x) Base.getindex(sp::SamplerTrivial) = sp.self # simple sampler carrying data (which can be anything) -struct SamplerSimple{T,S} <: Sampler +struct SamplerSimple{T,S,E} <: Sampler{E} self::T data::S end +SamplerSimple(x::T, data::S) where {T,S} = SamplerSimple{T,S,eltype(T)}(x, data) + Base.getindex(sp::SamplerSimple) = sp.self # simple sampler carrying a (type) tag T and data -struct SamplerTag{T,S} <: Sampler +struct SamplerTag{T,S,E} <: Sampler{E} data::S - SamplerTag{T}(s::S) where {T,S} = new{T,S}(s) + SamplerTag{T}(s::S) where {T,S} = new{T,S,eltype(T)}(s) end #### helper samplers +# TODO: make constraining constructors to enforce that those +# types are <: Sampler{T} + ##### Adapter to generate a randome value in [0, n] -struct LessThan{T<:Integer,S} <: Sampler +struct LessThan{T<:Integer,S} <: Sampler{T} sup::T s::S # the scalar specification/sampler to feed to rand end @@ -155,7 +165,7 @@ function rand(rng::AbstractRNG, sp::LessThan) end end -struct Masked{T<:Integer,S} <: Sampler +struct Masked{T<:Integer,S} <: Sampler{T} mask::T s::S end @@ -164,7 +174,7 @@ rand(rng::AbstractRNG, sp::Masked) = rand(rng, sp.s) & sp.mask ##### Uniform -struct UniformT{T} <: Sampler end +struct UniformT{T} <: Sampler{T} end uniform(::Type{T}) where {T} = UniformT{T}() diff --git a/test/random.jl b/test/random.jl index 392afc86a662c..2bfc6651d0120 100644 --- a/test/random.jl +++ b/test/random.jl @@ -289,8 +289,8 @@ let mt = MersenneTwister(0) @test rand!(mt, AF64)[end] == 0.957735065345398 @test rand!(mt, AF64)[end] == 0.6492481059865669 resize!(AF64, 2*length(mt.vals)) - @test invoke(rand!, Tuple{MersenneTwister,AbstractArray{Float64},Base.Random.SamplerTrivial{Base.Random.CloseOpen_64}}, - mt, AF64, Base.Random.SamplerTrivial(Base.Random.CloseOpen()))[end] == 0.1142787906708973 + @test invoke(rand!, Tuple{MersenneTwister,AbstractArray{Float64},Base.Random.SamplerTrivial{Base.Random.CloseOpen01_64}}, + mt, AF64, Base.Random.SamplerTrivial(Base.Random.CloseOpen01()))[end] == 0.1142787906708973 end # Issue #9037