Skip to content

Commit 8f8e43d

Browse files
committed
add more methods rand(rng, ...)
And similarly for rand!, randbool. Fixes #8360.
1 parent fad8b9d commit 8f8e43d

File tree

5 files changed

+95
-71
lines changed

5 files changed

+95
-71
lines changed

base/bitarray.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,10 @@ bitpack{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A)
331331

332332
## Random ##
333333

334-
function bitarray_rand_fill!(B::BitArray)
334+
function bitarray_rand_fill!(r, B::BitArray) # r is an AbstractRNG
335335
length(B) == 0 && return B
336336
Bc = B.chunks
337-
rand!(Bc)
337+
rand!(r, Bc)
338338
Bc[end] &= @_msk_end length(B)
339339
return B
340340
end

base/int.jl

+24-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ typealias SmallSigned Union(Int8,Int16,Int32)
88
typealias SmallUnsigned Union(Uint8,Uint16,Uint32)
99
end
1010

11+
typealias Signed64 Union(Int8,Int16,Int32,Int64)
12+
typealias Unsigned64 Union(Uint8,Uint16,Uint32,Uint64)
13+
typealias Integer64 Union(Signed64,Unsigned64)
14+
typealias Signed128 Union(Signed64, Int128)
15+
typealias Unsigned128 Union(Unsigned64, Uint128)
16+
typealias Integer128 Union(Signed128,Unsigned128)
17+
1118
## integer arithmetic ##
1219

1320
-(x::SmallSigned) = -int(x)
@@ -93,9 +100,6 @@ cld(x::Unsigned, y::Signed) = div(x,y)+(!signbit(y)&(rem(x,y)!=0))
93100

94101
# Don't promote integers for div/rem/mod since there no danger of overflow,
95102
# while there is a substantial performance penalty to 64-bit promotion.
96-
typealias Signed64 Union(Int8,Int16,Int32,Int64)
97-
typealias Unsigned64 Union(Uint8,Uint16,Uint32,Uint64)
98-
typealias Integer64 Union(Signed64,Unsigned64)
99103

100104
div{T<:Signed64} (x::T, y::T) = box(T,sdiv_int(unbox(T,x),unbox(T,y)))
101105
div{T<:Unsigned64}(x::T, y::T) = box(T,udiv_int(unbox(T,x),unbox(T,y)))
@@ -371,6 +375,23 @@ signed(x) = convert(Signed,x)
371375
unsigned(x) = convert(Unsigned,x)
372376
integer(x) = convert(Integer,x)
373377

378+
as_signed{T<:Signed128}(::Type{T}) = T
379+
as_signed(::Type{Uint8} ) = Int8
380+
as_signed(::Type{Uint16} ) = Int16
381+
as_signed(::Type{Uint32} ) = Int32
382+
as_signed(::Type{Uint64} ) = Int64
383+
as_signed(::Type{Uint128}) = Int128
384+
385+
as_unsigned{T<:Unsigned128}(::Type{T}) = T
386+
as_unsigned(::Type{Int8} ) = Uint8
387+
as_unsigned(::Type{Int16} ) = Uint16
388+
as_unsigned(::Type{Int32} ) = Uint32
389+
as_unsigned(::Type{Int64} ) = Uint64
390+
as_unsigned(::Type{Int128}) = Uint128
391+
392+
as_signed{T<:Integer128}(x::T) = convert(as_signed(T), x)
393+
as_unsigned{T<:Integer128}(x::T) = convert(as_unsigned(T), x)
394+
374395
round(x::Integer) = x
375396
trunc(x::Integer) = x
376397
floor(x::Integer) = x

base/random.jl

+52-46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Random
22

3-
using Base.dSFMT
3+
using Base: dSFMT, Integer128, Signed128, as_unsigned
44

55
export srand,
66
rand, rand!,
@@ -23,6 +23,25 @@ type MersenneTwister <: AbstractRNG
2323
MersenneTwister() = MersenneTwister(0)
2424
end
2525

26+
immutable GlobalRNG <: AbstractRNG
27+
end
28+
29+
typealias MT Union(GlobalRNG, MersenneTwister)
30+
31+
# random numbers of the following types are implemented:
32+
MTRealTypes = Union(Bool, Integer128, Float16, Float32, Float64)
33+
MTTypes = Union(MTRealTypes, [Complex{T} for T in MTRealTypes.types]...)
34+
35+
## rand: a non-specified RNG defaults to GlobalRNG()
36+
37+
rand() = rand(GlobalRNG())
38+
rand{T<:MTTypes}(::Type{T}) = rand(GlobalRNG(), T)
39+
rand(dims::Dims) = rand(GlobalRNG(), dims)
40+
rand(dims::Int...) = rand(dims)
41+
rand{T<:MTTypes}(::Type{T}, dims::Dims) = rand(GlobalRNG(), T, dims)
42+
rand{T<:MTTypes}(::Type{T}, d1::Int, dims::Int...) = rand(T, tuple(d1, dims...))
43+
rand!{T<:MTTypes}(A::AbstractArray{T}) = rand!(GlobalRNG(), A)
44+
2645
## initialization
2746

2847
__init__() = srand()
@@ -97,64 +116,49 @@ srand(r::MersenneTwister, filename::String, n::Integer=4) = srand(r, make_seed(f
97116

98117
## random floating point values
99118

100-
rand(::Type{Float64}) = dsfmt_gv_genrand_close_open()
101-
rand() = dsfmt_gv_genrand_close_open()
102-
103-
rand(::Type{Float32}) = float32(rand())
104-
rand(::Type{Float16}) = float16(rand())
105-
106-
rand{T<:Real}(::Type{Complex{T}}) = complex(rand(T),rand(T))
119+
rand(r::AbstractRNG) = rand(r, Float64)
107120

121+
# MersenneTwister
122+
rand(r::GlobalRNG, ::Type{Float64}) = dsfmt_gv_genrand_close_open()
123+
rand(r::MersenneTwister, ::Type{Float64}) = dsfmt_genrand_close_open(r.state)
108124

109-
rand(r::MersenneTwister) = dsfmt_genrand_close_open(r.state)
125+
rand{T<:Union(Float16, Float32)}(r::MT, ::Type{T}) = convert(T, rand(r))
110126

111-
## random integers
127+
## random integers (MersenneTwister)
112128

113-
dsfmt_randui32() = dsfmt_gv_genrand_uint32()
114-
dsfmt_randui64() = uint64(dsfmt_randui32()) | (uint64(dsfmt_randui32())<<32)
129+
rand(::GlobalRNG, ::Type{Uint32}) = dsfmt_gv_genrand_uint32()
130+
rand(r::MersenneTwister, ::Type{Uint32}) = dsfmt_genrand_uint32(r.state)
115131

116-
rand(::Type{Uint8}) = uint8(rand(Uint32))
117-
rand(::Type{Uint16}) = uint16(rand(Uint32))
118-
rand(::Type{Uint32}) = dsfmt_randui32()
119-
rand(::Type{Uint64}) = dsfmt_randui64()
120-
rand(::Type{Uint128}) = uint128(rand(Uint64))<<64 | rand(Uint64)
132+
rand(r::MT, ::Type{Bool}) = bool( rand(r, Uint32) & 1)
133+
rand(r::MT, ::Type{Uint8}) = uint8( rand(r, Uint32))
134+
rand(r::MT, ::Type{Uint16}) = uint16( rand(r, Uint32))
135+
rand(r::MT, ::Type{Uint64}) = uint64( rand(r, Uint32))<<32 | rand(r, Uint32)
136+
rand(r::MT, ::Type{Uint128}) = uint128(rand(r, Uint64))<<64 | rand(r, Uint64)
121137

122-
rand(::Type{Int8}) = int8(rand(Uint8))
123-
rand(::Type{Int16}) = int16(rand(Uint16))
124-
rand(::Type{Int32}) = int32(rand(Uint32))
125-
rand(::Type{Int64}) = int64(rand(Uint64))
126-
rand(::Type{Int128}) = int128(rand(Uint128))
138+
rand{T<:Signed128}(r::MT, ::Type{T}) = convert(T, rand(r, as_unsigned(T)))
127139

128-
# Arrays of random numbers
140+
## random complex values (AbstractRNG)
129141

130-
rand(::Type{Float64}, dims::Dims) = rand!(Array(Float64, dims))
131-
rand(::Type{Float64}, dims::Int...) = rand(Float64, dims)
142+
rand{T<:Real}(r::AbstractRNG, ::Type{Complex{T}}) = complex(rand(r, T), rand(r, T))
132143

133-
rand(dims::Dims) = rand(Float64, dims)
134-
rand(dims::Int...) = rand(Float64, dims)
144+
## Arrays of random numbers (AbstractRNG)
135145

136-
rand(r::AbstractRNG, dims::Dims) = rand!(r, Array(Float64, dims))
146+
rand(r::AbstractRNG, dims::Dims) = rand(r, Float64, dims)
137147
rand(r::AbstractRNG, dims::Int...) = rand(r, dims)
138148

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

146-
function rand!(r::AbstractRNG, A::AbstractArray)
155+
function rand!{T}(r::AbstractRNG, A::AbstractArray{T})
147156
for i=1:length(A)
148-
@inbounds A[i] = rand(r)
157+
@inbounds A[i] = rand(r, T)
149158
end
150159
A
151160
end
152161

153-
rand(T::Type, dims::Dims) = rand!(Array(T, dims))
154-
rand{T<:Number}(::Type{T}) = error("no random number generator for type $T; try a more specific type")
155-
rand{T<:Number}(::Type{T}, dims::Int...) = rand(T, dims)
156-
157-
158162
## Generate random integer within a range
159163

160164
# remainder function according to Knuth, where rem_knuth(a, 0) = a
@@ -240,16 +244,18 @@ end
240244
rand{T}(r::Range{T}, dims::Dims) = rand!(r, Array(T, dims))
241245
rand(r::Range, dims::Int...) = rand(r, dims)
242246

247+
## random BitArrays (AbstractRNG)
243248

244-
## random Bools
249+
rand!(r::AbstractRNG, B::BitArray) = Base.bitarray_rand_fill!(r, B)
245250

246-
rand!(B::BitArray) = Base.bitarray_rand_fill!(B)
251+
randbool(r::AbstractRNG, dims::Dims) = rand!(r, BitArray(dims))
252+
randbool(r::AbstractRNG, dims::Int...) = rand!(r, BitArray(dims))
247253

248-
randbool(dims::Dims) = rand!(BitArray(dims))
254+
randbool(dims::Dims) = rand!(BitArray(dims))
249255
randbool(dims::Int...) = rand!(BitArray(dims))
250256

251-
randbool() = ((dsfmt_randui32() & 1) == 1)
252-
rand(::Type{Bool}) = randbool()
257+
randbool(r::AbstractRNG=GlobalRNG()) = rand(r, Bool)
258+
253259

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

doc/stdlib/base.rst

+11-19
Original file line numberDiff line numberDiff line change
@@ -3932,43 +3932,35 @@ Random Numbers
39323932

39333933
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.
39343934

3935+
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.
3936+
3937+
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).
3938+
39353939
.. function:: srand([rng], [seed])
39363940

3937-
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.
3941+
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.
39383942

39393943
.. function:: MersenneTwister([seed])
39403944

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

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

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

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

3949-
Populate the array A with random number generated from the specified RNG.
3950-
3951-
.. function:: rand(rng::AbstractRNG, [dims...])
3952-
3953-
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.
3954-
3955-
.. function:: rand(dims or [dims...])
3956-
3957-
Generate a random ``Float64`` array of the size specified by dims
3958-
3959-
.. function:: rand(t::Type, [dims...])
3960-
3961-
Generate a random number or array of random numbes of the given type.
3953+
Populate the array A with random values.
39623954

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

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

3967-
.. function:: randbool([dims...])
3959+
.. function:: randbool([rng], [dims...])
39683960

3969-
Generate a random boolean value. Optionally, generate an array of random boolean values.
3961+
Generate a random boolean value. Optionally, generate a ``BitArray`` of random boolean values.
39703962

3971-
.. function:: randn([rng], dims or [dims...])
3963+
.. function:: randn([rng], [dims...])
39723964

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

test/random.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,17 @@ srand(0); rand(); x = rand(384);
1919
# Try a seed larger than 2^32
2020
@test rand(MersenneTwister(5294967296)) == 0.3498809918210497
2121

22-
# Test array filling, Issue #7643
22+
# Test array filling, Issues #7643, #8360
2323
@test rand(MersenneTwister(0), 1) == [0.8236475079774124]
2424
A = zeros(2, 2)
2525
rand!(MersenneTwister(0), A)
2626
@test A == [0.8236475079774124 0.16456579813368521;
2727
0.9103565379264364 0.17732884646626457]
28+
@test rand(MersenneTwister(0), Int64, 1) == [172014471070449746]
29+
A = zeros(Int64, 2, 2)
30+
rand!(MersenneTwister(0), A)
31+
@test A == [ 172014471070449746 -193283627354378518;
32+
-4679130500738884555 -9008350441255501549]
2833

2934
# randn
3035
@test randn(MersenneTwister(42)) == -0.5560268761463861

0 commit comments

Comments
 (0)