Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions base/random/RNGs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)


Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
33 changes: 17 additions & 16 deletions base/random/generation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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 &&
Expand All @@ -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
Expand All @@ -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}}) =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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

Expand Down
44 changes: 27 additions & 17 deletions base/random/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export srand,

abstract type AbstractRNG end


### integers

# we define types which encode the generation of a specific number of bits
Expand Down Expand Up @@ -67,23 +68,25 @@ 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

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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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}()

Expand Down
4 changes: 2 additions & 2 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down