Skip to content

Commit

Permalink
add more methods rand(rng, ...)
Browse files Browse the repository at this point in the history
And similarly for rand!, randbool.
Fixes JuliaLang#8360.
  • Loading branch information
rfourquet committed Oct 30, 2014
1 parent 876d2dd commit a1e4bac
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 65 deletions.
4 changes: 2 additions & 2 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ bitpack{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A)

## Random ##

function bitarray_rand_fill!(B::BitArray)
function bitarray_rand_fill!(rng, B::BitArray) # rng is an AbstractRNG
length(B) == 0 && return B
Bc = B.chunks
rand!(Bc)
rand!(rng, Bc)
Bc[end] &= @_msk_end length(B)
return B
end
Expand Down
88 changes: 45 additions & 43 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,49 +115,53 @@ srand(filename::String, n::Integer=4) = srand(GLOBAL_RNG, filename, n)
const GLOBAL_RNG = MersenneTwister()
globalRNG() = GLOBAL_RNG

## random floating point values
# rand: a non-specified RNG defaults to GLOBAL_RNG

rand(r::MersenneTwister=GLOBAL_RNG) = rand_close_open(r)
rand() = rand(GLOBAL_RNG)
rand(T::Type) = rand(GLOBAL_RNG, T)
rand(::()) = rand(GLOBAL_RNG, ()) # needed to resolve ambiguity
rand(dims::Dims) = rand(GLOBAL_RNG, dims)
rand(dims::Int...) = rand(dims)
rand(T::Type, dims::Dims) = rand(GLOBAL_RNG, T, dims)
rand(T::Type, d1::Int, dims::Int...) = rand(T, tuple(d1, dims...))
rand!(A::AbstractArray) = rand!(GLOBAL_RNG, A)

rand(::Type{Float64}) = rand()
## random floating point values

rand(::Type{Float32}) = float32(rand())
rand(::Type{Float16}) = float16(rand())
rand(r::AbstractRNG) = rand(r, Float64)

rand{T<:Real}(::Type{Complex{T}}) = complex(rand(T),rand(T))
# MersenneTwister
rand(r::MersenneTwister, ::Type{Float64}) = rand_close_open(r)
rand{T<:Union(Float16, Float32)}(r::MersenneTwister, ::Type{T}) = convert(T, rand(r, Float64))

## random integers
## random integers (MersenneTwister)

rand(::Type{Uint8}) = rand(Uint32) % Uint8
rand(::Type{Uint16}) = rand(Uint32) % Uint16
rand(::Type{Uint32}) = rand_ui32(GLOBAL_RNG)
rand(::Type{Uint64}) = uint64(rand(Uint32)) <<32 | rand(Uint32)
rand(::Type{Uint128}) = uint128(rand(Uint64))<<64 | rand(Uint64)
rand(r::MersenneTwister, ::Type{Uint8}) = rand(r, Uint32) % Uint8
rand(r::MersenneTwister, ::Type{Uint16}) = rand(r, Uint32) % Uint16
rand(r::MersenneTwister, ::Type{Uint32}) = rand_ui32(r)
rand(r::MersenneTwister, ::Type{Uint64}) = uint64(rand(r, Uint32)) <<32 | rand(r, Uint32)
rand(r::MersenneTwister, ::Type{Uint128}) = uint128(rand(r, Uint64))<<64 | rand(r, Uint64)

rand(::Type{Int8}) = rand(Uint32) % Int8
rand(::Type{Int16}) = rand(Uint32) % Int16
rand(::Type{Int32}) = reinterpret(Int32,rand(Uint32))
rand(::Type{Int64}) = reinterpret(Int64,rand(Uint64))
rand(::Type{Int128}) = reinterpret(Int128,rand(Uint128))
rand(r::MersenneTwister, ::Type{Int8}) = rand(r, Uint32) % Int8
rand(r::MersenneTwister, ::Type{Int16}) = rand(r, Uint32) % Int16
rand(r::MersenneTwister, ::Type{Int32}) = reinterpret(Int32, rand(r, Uint32))
rand(r::MersenneTwister, ::Type{Int64}) = reinterpret(Int64, rand(r, Uint64))
rand(r::MersenneTwister, ::Type{Int128}) = reinterpret(Int128, rand(r, Uint128))

# Arrays of random numbers
## random complex values

rand(::Type{Float64}, dims::Dims) = rand!(Array(Float64, dims))
rand(::Type{Float64}, dims::Int...) = rand(Float64, dims)
rand{T<:Real}(r::AbstractRNG, ::Type{Complex{T}}) = complex(rand(r, T), rand(r, T))

rand(dims::Dims) = rand(Float64, dims)
rand(dims::Int...) = rand(Float64, dims)
## Arrays of random numbers

rand(r::AbstractRNG) = rand(r, Float64)
rand(r::AbstractRNG, dims::Dims) = rand!(r, Array(Float64, dims))
rand(r::AbstractRNG, dims::Dims) = rand(r, Float64, dims)
rand(r::AbstractRNG, dims::Int...) = rand(r, dims)

function rand!{T}(A::Array{T})
for i = 1:length(A)
A[i] = rand(T)
end
A
end
rand(r::AbstractRNG, T::Type, dims::Dims) = rand!(r, Array(T, dims))
rand(r::AbstractRNG, T::Type, d1::Int, dims::Int...) = rand(r, T, tuple(d1, dims...))
# note: the above method would trigger an ambiguity warning if d1 was not separated out:
# rand(r, ()) would match both this method and rand(r, dims::Dims)
# moreover, a call like rand(r, NotImplementedType()) would be an infinite loop

function rand!{T}(r::AbstractRNG, A::AbstractArray{T})
for i = 1:length(A)
Expand All @@ -166,6 +170,8 @@ function rand!{T}(r::AbstractRNG, A::AbstractArray{T})
A
end

# MersenneTwister

function rand_AbstractArray_Float64!(r::MersenneTwister, A::AbstractArray{Float64})
n = length(A)
# what follows is equivalent to this simple loop but more efficient:
Expand Down Expand Up @@ -201,14 +207,6 @@ function rand!(r::MersenneTwister, A::Array{Float64})
A
end

rand!(A::AbstractArray{Float64}) = rand!(GLOBAL_RNG, A)
rand!(A::Array{Float64}) = rand!(GLOBAL_RNG, A)

rand(T::Type, dims::Dims) = rand!(Array(T, dims))
rand{T<:Number}(::Type{T}) = error("no random number generator for type $T; try a more specific type")
rand{T<:Number}(::Type{T}, dims::Int...) = rand(T, dims)


## Generate random integer within a range

# remainder function according to Knuth, where rem_knuth(a, 0) = a
Expand Down Expand Up @@ -295,16 +293,20 @@ end
rand{T}(r::Range{T}, dims::Dims) = rand!(r, Array(T, dims))
rand(r::Range, dims::Int...) = rand(r, dims)

## random BitArrays (AbstractRNG)

## random Bools
rand!(r::AbstractRNG, B::BitArray) = Base.bitarray_rand_fill!(r, B)

rand!(B::BitArray) = Base.bitarray_rand_fill!(B)
randbool(r::AbstractRNG, dims::Dims) = rand!(r, BitArray(dims))
randbool(r::AbstractRNG, dims::Int...) = rand!(r, BitArray(dims))

randbool(dims::Dims) = rand!(BitArray(dims))
randbool(dims::Dims) = rand!(BitArray(dims))
randbool(dims::Int...) = rand!(BitArray(dims))

randbool() = ((rand(Uint32) & 1) == 1)
rand(::Type{Bool}) = randbool()
randbool(r::MersenneTwister=GLOBAL_RNG) = ((rand(r, Uint32) & 1) == 1)

rand(r::MersenneTwister, ::Type{Bool}) = randbool(r)


## randn() - Normally distributed random numbers using Ziggurat algorithm

Expand Down
30 changes: 11 additions & 19 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3931,43 +3931,35 @@ Random Numbers

Random number generation in Julia uses the `Mersenne Twister library <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/#dSFMT>`_. Julia has a global RNG, which is used by default. Multiple RNGs can be plugged in using the ``AbstractRNG`` object, which can then be used to have multiple streams of random numbers. Currently, only ``MersenneTwister`` is supported.

Most functions related to random generation accept an optional ``AbstractRNG`` as the first argument, ``rng`` , which defaults to the global one if not provided. Morever, some of them accept optionally dimension specifications ``dims...`` (which can be given as a tuple) to generate arrays of random values.

A ``MersenneTwister`` RNG can generate random numbers of the following types: ``Float16, Float32, Float64, Bool, Int16, Uint16, Int32, Uint32, Int64, Uint64, Int128, Uint128`` (or complex numbers or arrays of those types). Random floating point numbers are generated uniformly in [0,1).

.. function:: srand([rng], [seed])

Reseed the random number generator. If a ``seed`` is provided, the RNG will give a reproducible sequence of numbers, otherwise Julia will get entropy from the system. The ``seed`` may be a non-negative integer, a vector of ``Uint32`` integers or a filename, in which case the seed is read from a file. If the argument ``rng`` is not provided, the default global RNG is seeded.
Reseed the random number generator. If a ``seed`` is provided, the RNG will give a reproducible sequence of numbers, otherwise Julia will get entropy from the system. The ``seed`` may be a non-negative integer, a vector of ``Uint32`` integers or a filename, in which case the seed is read from a file.

.. function:: MersenneTwister([seed])

Create a ``MersenneTwister`` RNG object. Different RNG objects can have their own seeds, which may be useful for generating different streams of random numbers.

.. function:: rand() -> Float64
.. function:: rand([rng], [t::Type], [dims...])

Generate a ``Float64`` random number uniformly in [0,1)
Generate a random value or an array of random values of the given type, ``t``, which defaults to ``Float64``.

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

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

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

Generate a random ``Float64`` number or array of the size specified by dims, using the specified RNG object. Currently, ``MersenneTwister`` is the only available Random Number Generator (RNG), which may be seeded using srand.

.. function:: rand(dims or [dims...])

Generate a random ``Float64`` array of the size specified by dims

.. function:: rand(t::Type, [dims...])

Generate a random number or array of random numbes of the given type.
Populate the array A with random values.

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

Pick a random element or array of random elements from range ``r`` (for example, ``1:n`` or ``0:2:10``).

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

Generate a random boolean value. Optionally, generate an array of random boolean values.
Generate a random boolean value. Optionally, generate a ``BitArray`` of random boolean values.

.. function:: randn([rng], dims or [dims...])
.. function:: randn([rng], [dims...])

Generate a normally-distributed random number with mean 0 and standard deviation 1. Optionally generate an array of normally-distributed random numbers.

Expand Down
7 changes: 6 additions & 1 deletion test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ srand(0); rand(); x = rand(384);
# Try a seed larger than 2^32
@test rand(MersenneTwister(5294967296)) == 0.3498809918210497

# Test array filling, Issue #7643
# Test array filling, Issues #7643, #8360
@test rand(MersenneTwister(0), 1) == [0.8236475079774124]
A = zeros(2, 2)
rand!(MersenneTwister(0), A)
@test A == [0.8236475079774124 0.16456579813368521;
0.9103565379264364 0.17732884646626457]
@test rand(MersenneTwister(0), Int64, 1) == [172014471070449746]
A = zeros(Int64, 2, 2)
rand!(MersenneTwister(0), A)
@test A == [ 172014471070449746 -193283627354378518;
-4679130500738884555 -9008350441255501549]

# randn
@test randn(MersenneTwister(42)) == -0.5560268761463861
Expand Down

0 comments on commit a1e4bac

Please sign in to comment.