Skip to content

Commit

Permalink
Revert #8309 untill long ranges are supported.
Browse files Browse the repository at this point in the history
cc @rfourquet

This reverts commit 7e87797.
This reverts commit c754a60.
This reverts commit 38bef62.
This reverts commit d9814ff.
This reverts commit 91aa94f.
This reverts commit 57bd2b7.
This reverts commit 9d0282e.
This reverts commit 6d329ce.
This reverts commit e2b14a1.
  • Loading branch information
ivarne committed Oct 3, 2014
1 parent e1e47ee commit 6117328
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 68 deletions.
98 changes: 54 additions & 44 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type MersenneTwister <: AbstractRNG
MersenneTwister(seed=0) = MersenneTwister(make_seed(seed))
end

function srand(r::MersenneTwister, seed)
function srand(r::MersenneTwister, seed)
r.seed = seed
dsfmt_init_gen_rand(r.state, seed)
return r
Expand Down Expand Up @@ -146,77 +146,87 @@ rand{T<:Number}(::Type{T}) = error("no random number generator for type $T; try
rand{T<:Number}(::Type{T}, dims::Int...) = rand(T, dims)


## Generate random integer within a range 1:n
## Generate random integer within a range

# maxmultiple: precondition: k>0
# maximum multiple of k <= 2^numbits(k), decremented by one
maxmultiple(k::Uint32) = itrunc(Uint32, div(0x0000000100000000, k)*k - 1)
maxmultiple(k::Uint64) = itrunc(Uint64, div(0x00000000000000010000000000000000, k)*k - 1)
# maximum multiple of k <= typemax(Uint128), decremented by one
maxmultiple(k::Uint128) = div(typemax(Uint128), k)*k - 1
# 32 or 64 bits version depending on size
maxmultiplemix(k::Uint64) = k >> 32 == 0 ? uint64(maxmultiple(itrunc(Uint32, k))) : maxmultiple(k)
# remainder function according to Knuth, where rem_knuth(a, 0) = a
rem_knuth(a::Uint, b::Uint) = a % (b + (b == 0)) + a * (b == 0)
rem_knuth{T<:Unsigned}(a::T, b::T) = b != 0 ? a % b : a

immutable RandIntGen{T<:Integer, U<:Union(Uint32, Uint64, Uint128)}
k::U # range length
u::U # rejection threshold
# maximum multiple of k <= 2^bits(T) decremented by one,
# that is 0xFFFFFFFF if k = typemax(T) - typemin(T) with intentional underflow
maxmultiple(k::Uint32) = itrunc(Uint32, div(0x0000000100000000,k + (k == 0))*k - 1)
maxmultiple(k::Uint64) = itrunc(Uint64, div(0x00000000000000010000000000000000, k + (k == 0))*k - 1)
# maximum multiple of k within 1:typemax(Uint128)
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) = itrunc(Uint64, div((k >> 32 != 0)*0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000, k + (k == 0))*k - 1)

function RandIntGen(k::U)
k < 1 && error("No integers in the range [1, $k]. Did you try to pick an element from a empty collection?")
new(k, isa(k, Uint64) ? maxmultiplemix(k) : maxmultiple(k))
end
immutable RandIntGen{T<:Integer, U<:Unsigned}
k::U # range length (or zero for full range)
u::U # rejection threshold
end
# generators with 32, 128 bits entropy
RandIntGen{U<:Union(Uint32, Uint128)}(T::Type, k::U) = RandIntGen{T, U}(k, maxmultiple(k))
# mixed 32/64 bits entropy generator
RandIntGen(T::Type, k::Uint64) = RandIntGen{T,Uint64}(k, maxmultiplemix(k))


# generator API
# randintgen(k) returns a helper object for generating random integers in the range 1:k
randintgen{T<:Unsigned}(k::T) = RandIntGen{T, T}(k)
randintgen{T<:Unsigned}(k::T) = k<1 ? error("range must be non-empty") : RandIntGen(T, k)
# specialized versions
for (T, U) in [(Uint8, Uint32), (Uint16, Uint32),
(Int8, Uint32), (Int16, Uint32), (Int32, Uint32), (Int64, Uint64), (Int128, Uint128),
(Bool, Uint32), (Char, Uint32)]

@eval randintgen(k::$T) = RandIntGen{$T,$U}(convert($U, k))
end

@inline function rand_lessthan{U}(u::U)
while true
x = rand(U)
x <= u && return x
end
@eval randintgen(k::$T) = k<1 ? error("range must be non-empty") : RandIntGen($T, convert($U, k)) # overflow ok
end

# this function uses 32 bit entropy for small ranges of length <= typemax(Uint32) + 1
# RandIntGen is responsible for providing the right value of k
function rand{T}(g::RandIntGen{T,Uint64})
x = (g.k - 1) >> 32 == 0 ?
uint64(rand_lessthan(itrunc(Uint32, g.u))) :
rand_lessthan(g.u)
return reinterpret(T, one(Uint64) + x % g.k)
function rand{T<:Union(Uint64, Int64)}(g::RandIntGen{T,Uint64})
local x::Uint64
if (g.k - 1) >> 32 == 0
x = rand(Uint32)
while x > g.u
x = rand(Uint32)
end
else
x = rand(Uint64)
while x > g.u
x = rand(Uint64)
end
end
return reinterpret(T, one(Uint64) + rem_knuth(x, g.k))
end

rand{T,U}(g::RandIntGen{T,U}) = itrunc(T, one(U) + rand_lessthan(g.u) % g.k)


## Randomly draw a sample from an AbstractArray r
# (e.g. r is a range 0:2:8 or a vector [2, 3, 5, 7])

rand(r::AbstractArray) = r[rand(randintgen(length(r)))]
function rand{T<:Integer, U<:Unsigned}(g::RandIntGen{T,U})
x = rand(U)
while x > g.u
x = rand(U)
end
itrunc(T, one(U) + rem_knuth(x, g.k))
end

# Arrays of random integers
rand{T}(r::Range{T}) = r[rand(randintgen(length(r)))]

rand!(r::Range, A::AbstractArray) = rand!(r, A, ())
function rand!(g::RandIntGen, A::AbstractArray)
for i = 1 : length(A)
@inbounds A[i] = rand(g)
end
return A
end

# TODO: this more general version is "disabled" until #8246 is resolved
function rand!(r::AbstractArray, A::AbstractArray, ::())
function rand!(r::Range, A::AbstractArray)
g = randintgen(length(r))
for i = 1 : length(A)
@inbounds A[i] = r[rand(g)]
end
return A
end

rand{T}(r::AbstractArray{T}, dims::Dims) = rand!(r, Array(T, dims), ())
rand(r::AbstractArray, dims::Int...) = rand(r, dims)
rand{T}(r::Range{T}, dims::Dims) = rand!(r, Array(T, dims))
rand(r::Range, dims::Int...) = rand(r, dims)


## random Bools
Expand Down
10 changes: 3 additions & 7 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3946,7 +3946,7 @@ Random number generation in Julia uses the `Mersenne Twister library <http://www

.. function:: rand!([rng], A)

Populate the array A with random numbers generated from the specified RNG.
Populate the array A with random number generated from the specified RNG.

.. function:: rand(rng::AbstractRNG, [dims...])

Expand All @@ -3960,13 +3960,9 @@ Random number generation in Julia uses the `Mersenne Twister library <http://www

Generate a random number or array of random numbes of the given type.

.. function:: rand(coll, [dims...])
.. function:: rand(r, [dims...])

Pick a random element or array of random elements from the indexable collection ``coll`` (for example, ``1:n`` or ``['x','y','z']``).

.. function:: rand!(r, A)

Populate the array A with random values drawn uniformly from the range ``r``.
Pick a random element or array of random elements from range ``r`` (for example, ``1:n`` or ``0:2:10``).

.. function:: randbool([dims...])

Expand Down
20 changes: 3 additions & 17 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ rand!(MersenneTwister(0), A)
@test A == [0.8236475079774124 0.16456579813368521;
0.9103565379264364 0.17732884646626457]

@test rand(0:3:1000) in 0:3:1000
coll = {2, uint128(128), big(619), "string", 'c'}
@test rand(coll) in coll
@test issubset(rand(coll, 2, 3), coll)

# randn
@test randn(MersenneTwister(42)) == -0.5560268761463861
A = zeros(2, 2)
Expand All @@ -49,18 +44,9 @@ for T in (Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64, Int128, Uint
@test mod(r,2)==1

if T<:Integer && T!==Char
if T.size < Int.size
x = rand(typemin(T):typemax(T))
@test isa(x,T)
@test typemin(T) <= x <= typemax(T)
else # we bound the length of the range to typemax(T) so that there is no overflow
for (a, b) in ((typemin(T),typemin(T)+typemax(T)-one(T)),
(one(T),typemax(T)))
x = rand(a:b)
@test isa(x,T)
@test a <= x <= b
end
end
x = rand(typemin(T):typemax(T))
@test isa(x,T)
@test typemin(T) <= x <= typemax(T)
end
end

Expand Down

0 comments on commit 6117328

Please sign in to comment.