Skip to content

Commit ceb2cd2

Browse files
committed
write non-zero bits only in lower bit of each byte, and get faster
1 parent 6674cac commit ceb2cd2

File tree

1 file changed

+33
-5
lines changed

1 file changed

+33
-5
lines changed

stdlib/Random/src/RNGs.jl

+33-5
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,39 @@ end
603603

604604
#### arrays of Bool
605605

606-
function rand!(r::MersenneTwister, A::Array{Bool}, sp::SamplerType{Bool})
607-
GC.@preserve A rand!(r,
608-
UnsafeView(Ptr{UInt8}(pointer(A)), length(A)),
609-
SamplerType{UInt8}())
610-
A
606+
# similar to Array{UInt8}, but we need to mask the result so that only the LSB
607+
# in each byte can be non-zero
608+
609+
function rand!(r::MersenneTwister, A1::Array{Bool}, sp::SamplerType{Bool})
610+
n1 = length(A1)
611+
n128 = n1 ÷ 16
612+
613+
A = UnsafeView{UInt128}(pointer(A1), n128)
614+
rand!(r, UnsafeView{Float64}(A.ptr, 2*n128), CloseOpen12())
615+
mask = 0x01010101010101010101010101010101
616+
# without masking, non-zero bits could be observed in other
617+
# positions than the LSB of each byte
618+
619+
if n128 > 0
620+
# we need up to 15 bits of entropy for the last loop;
621+
# A[1] % UInt64 contains 52 bits of entropy, but 8
622+
# of them will be used for A[i] itself (the first of
623+
# each byte). To compensate, we xor with (A[1] >> 65),
624+
# which gets the entropy from the second bit of each byte
625+
# of the upper-half of A[i].
626+
bits = (A[1] % UInt64) (A[1] >> 65) % UInt64
627+
else
628+
bits = rand(r, UInt52Raw())
629+
end
630+
for i = 1:n128
631+
# << 5 to initialize the first bit of the 8th byte
632+
A[i] = (A[i] A[i] << 5) & mask
633+
end
634+
for i = 16*n128+1:n1
635+
@inbounds A1[i] = bits % Bool
636+
bits >>= 1
637+
end
638+
A1
611639
end
612640

613641

0 commit comments

Comments
 (0)