|
104 | 104 |
|
105 | 105 | @inline rand_ui52_raw_inbounds(r::MersenneTwister) = reinterpret(UInt64, rand_inbounds(r, Close1Open2))
|
106 | 106 | @inline rand_ui52_raw(r::MersenneTwister) = (reserve_1(r); rand_ui52_raw_inbounds(r))
|
107 |
| -@inline rand_ui52(r::MersenneTwister) = rand_ui52_raw(r) & 0x000fffffffffffff |
108 | 107 | @inline rand_ui2x52_raw(r::MersenneTwister) = rand_ui52_raw(r) % UInt128 << 64 | rand_ui52_raw(r)
|
109 | 108 |
|
110 | 109 | function srand(r::MersenneTwister, seed::Vector{UInt32})
|
@@ -241,7 +240,8 @@ rand(r::Union{RandomDevice,MersenneTwister}, ::Type{Float32}) =
|
241 | 240 |
|
242 | 241 | ## random integers
|
243 | 242 |
|
244 |
| -@inline rand_ui52(r::AbstractRNG) = reinterpret(UInt64, rand(r, Close1Open2)) & 0x000fffffffffffff |
| 243 | +@inline rand_ui52_raw(r::AbstractRNG) = reinterpret(UInt64, rand(r, Close1Open2)) |
| 244 | +@inline rand_ui52(r::AbstractRNG) = rand_ui52_raw(r) & 0x000fffffffffffff |
245 | 245 |
|
246 | 246 | # MersenneTwister
|
247 | 247 |
|
@@ -1320,41 +1320,62 @@ randsubseq!(S::AbstractArray, A::AbstractArray, p::Real) = randsubseq!(GLOBAL_RN
|
1320 | 1320 | randsubseq{T}(r::AbstractRNG, A::AbstractArray{T}, p::Real) = randsubseq!(r, T[], A, p)
|
1321 | 1321 | randsubseq(A::AbstractArray, p::Real) = randsubseq(GLOBAL_RNG, A, p)
|
1322 | 1322 |
|
| 1323 | +"Return a random `Int` (masked with `mask`) in ``[0, n)``, when `n <= 2^52`." |
| 1324 | +@inline function rand_lt(r::AbstractRNG, n::Int, mask::Int=nextpow2(n)-1) |
| 1325 | + # this duplicates the functionality of RangeGenerator objects, |
| 1326 | + # to optimize this special case |
| 1327 | + while true |
| 1328 | + x = (rand_ui52_raw(r) % Int) & mask |
| 1329 | + x < n && return x |
| 1330 | + end |
| 1331 | +end |
1323 | 1332 |
|
1324 | 1333 | function shuffle!(r::AbstractRNG, a::AbstractVector)
|
1325 |
| - for i = length(a):-1:2 |
1326 |
| - j = rand(r, 1:i) |
| 1334 | + n = length(a) |
| 1335 | + @assert n <= Int64(2)^52 |
| 1336 | + mask = nextpow2(n) - 1 |
| 1337 | + for i = n:-1:2 |
| 1338 | + (mask >> 1) == i && (mask >>= 1) |
| 1339 | + j = 1 + rand_lt(r, i, mask) |
1327 | 1340 | a[i], a[j] = a[j], a[i]
|
1328 | 1341 | end
|
1329 | 1342 | return a
|
1330 | 1343 | end
|
| 1344 | + |
1331 | 1345 | shuffle!(a::AbstractVector) = shuffle!(GLOBAL_RNG, a)
|
1332 | 1346 |
|
1333 | 1347 | shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copy(a))
|
1334 | 1348 | shuffle(a::AbstractVector) = shuffle(GLOBAL_RNG, a)
|
1335 | 1349 |
|
1336 | 1350 | function randperm(r::AbstractRNG, n::Integer)
|
1337 | 1351 | a = Array(typeof(n), n)
|
| 1352 | + @assert n <= Int64(2)^52 |
1338 | 1353 | if n == 0
|
1339 | 1354 | return a
|
1340 | 1355 | end
|
1341 | 1356 | a[1] = 1
|
1342 |
| - @inbounds for i = 2:n |
1343 |
| - j = rand(r, 1:i) |
| 1357 | + mask = 3 |
| 1358 | + @inbounds for i = 2:Int(n) |
| 1359 | + j = 1 + rand_lt(r, i, mask) |
1344 | 1360 | a[i] = a[j]
|
1345 | 1361 | a[j] = i
|
| 1362 | + i == 1+mask && (mask = 2mask + 1) |
1346 | 1363 | end
|
1347 | 1364 | return a
|
1348 | 1365 | end
|
1349 | 1366 | randperm(n::Integer) = randperm(GLOBAL_RNG, n)
|
1350 | 1367 |
|
1351 | 1368 | function randcycle(r::AbstractRNG, n::Integer)
|
1352 | 1369 | a = Array(typeof(n), n)
|
| 1370 | + n == 0 && return a |
| 1371 | + @assert n <= Int64(2)^52 |
1353 | 1372 | a[1] = 1
|
1354 |
| - @inbounds for i = 2:n |
1355 |
| - j = rand(r, 1:i-1) |
| 1373 | + mask = 3 |
| 1374 | + @inbounds for i = 2:Int(n) |
| 1375 | + j = 1 + rand_lt(r, i-1, mask) |
1356 | 1376 | a[i] = a[j]
|
1357 | 1377 | a[j] = i
|
| 1378 | + i == 1+mask && (mask = 2mask + 1) |
1358 | 1379 | end
|
1359 | 1380 | return a
|
1360 | 1381 | end
|
|
0 commit comments