Skip to content

Commit 261f323

Browse files
committed
implement rand(::BigFloat) (close #13948)
1 parent 713986d commit 261f323

File tree

4 files changed

+90
-14
lines changed

4 files changed

+90
-14
lines changed

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ Library improvements
200200
* Mutating versions of `randperm` and `randcycle` have been added:
201201
`randperm!` and `randcycle!` ([#22723]).
202202

203+
* `BigFloat` random numbers can now be generated ([#22720]).
204+
203205
Compiler/Runtime improvements
204206
-----------------------------
205207

base/random/generation.jl

+69
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,67 @@ rand_generic(r::AbstractRNG, ::Close1Open2_64) =
2929

3030
rand_generic(r::AbstractRNG, ::CloseOpen_64) = rand(r, Close1Open2()) - 1.0
3131

32+
#### BigFloat
33+
34+
const bits_in_Limb = sizeof(Limb)<<3
35+
const Limb_high_bit = one(Limb) << (bits_in_Limb-1)
36+
37+
struct BigFloatRandGenerator
38+
prec::Int
39+
nlimbs::Int
40+
limbs::Vector{Limb}
41+
shift::UInt
42+
43+
function BigFloatRandGenerator(prec::Int=precision(BigFloat))
44+
nlimbs = (prec-1) ÷ bits_in_Limb + 1
45+
limbs = Vector{Limb}(nlimbs)
46+
shift = nlimbs * bits_in_Limb - prec
47+
new(prec, nlimbs, limbs, shift)
48+
end
49+
end
50+
51+
function _rand(rng::AbstractRNG, gen::BigFloatRandGenerator)
52+
z = BigFloat()
53+
limbs = gen.limbs
54+
rand!(rng, limbs)
55+
@inbounds begin
56+
limbs[1] <<= gen.shift
57+
randbool = iszero(limbs[end] & Limb_high_bit)
58+
limbs[end] |= Limb_high_bit
59+
end
60+
z.sign = 1
61+
unsafe_copy!(z.d, pointer(limbs), gen.nlimbs)
62+
(z, randbool)
63+
end
64+
65+
function rand_generic(rng::AbstractRNG, ::Close1Open2{BigFloat},
66+
gen::BigFloatRandGenerator=BigFloatRandGenerator())
67+
z = _rand(rng, gen)[1]
68+
z.exp = 1
69+
z
70+
end
71+
72+
function rand_generic(rng::AbstractRNG, ::CloseOpen{BigFloat},
73+
gen::BigFloatRandGenerator=BigFloatRandGenerator())
74+
z, randbool = _rand(rng, gen)
75+
z.exp = 0
76+
randbool &&
77+
ccall((:mpfr_sub_d, :libmpfr), Int32,
78+
(Ptr{BigFloat}, Ptr{BigFloat}, Cdouble, Int32),
79+
&z, &z, 0.5, Base.MPFR.ROUNDING_MODE[])
80+
z
81+
end
82+
83+
# alternative, with 1 bit less of precision
84+
# TODO: make an API for requesting full or not-full precision
85+
function rand_generic(rng::AbstractRNG, ::CloseOpen{BigFloat}, ::Val{false},
86+
gen::BigFloatRandGenerator=BigFloatRandGenerator())
87+
z = rand_generic(rng, Close1Open2(BigFloat), gen)
88+
ccall((:mpfr_sub_ui, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Culong, Int32),
89+
&z, &z, 1, Base.MPFR.ROUNDING_MODE[])
90+
z
91+
end
92+
3293
### random integers
3394

3495
rand_ui10_raw(r::AbstractRNG) = rand(r, UInt16)
@@ -90,6 +151,14 @@ function rand!(r::AbstractRNG, A::AbstractArray, I::FloatInterval)
90151
A
91152
end
92153

154+
function rand!(rng::AbstractRNG, A::AbstractArray, I::FloatInterval{BigFloat})
155+
gen = BigFloatRandGenerator()
156+
for i in eachindex(A)
157+
@inbounds A[i] = rand_generic(rng, I, gen)
158+
end
159+
A
160+
end
161+
93162
rand!(A::AbstractArray, I::FloatInterval) = rand!(GLOBAL_RNG, A, I)
94163

95164
## Generate random integer within a range

doc/src/stdlib/numbers.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@ dimension specifications `dims...` (which can be given as a tuple) to generate a
143143
values.
144144

145145
A `MersenneTwister` or `RandomDevice` RNG can generate random numbers of the following types:
146-
[`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`Bool`](@ref), [`Int8`](@ref),
147-
[`UInt8`](@ref), [`Int16`](@ref), [`UInt16`](@ref), [`Int32`](@ref), [`UInt32`](@ref),
148-
[`Int64`](@ref), [`UInt64`](@ref), [`Int128`](@ref), [`UInt128`](@ref), [`BigInt`](@ref)
149-
(or complex numbers of those types). Random floating point numbers are generated uniformly
150-
in ``[0, 1)``. As `BigInt` represents unbounded integers, the interval must be specified
151-
(e.g. `rand(big(1:6))`).
146+
[`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`Float64`](@ref),[`Bool`](@ref),
147+
[`Int8`](@ref), [`UInt8`](@ref), [`Int16`](@ref), [`UInt16`](@ref), [`Int32`](@ref),
148+
[`UInt32`](@ref), [`Int64`](@ref), [`UInt64`](@ref), [`Int128`](@ref), [`UInt128`](@ref),
149+
[`BigInt`](@ref) (or complex numbers of those types).
150+
Random floating point numbers are generated uniformly in ``[0, 1)``. As `BigInt` represents
151+
unbounded integers, the interval must be specified (e.g. `rand(big(1:6))`).
152152

153153
```@docs
154154
Base.Random.srand

test/random.jl

+13-8
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ end
308308
for rng in ([], [MersenneTwister(0)], [RandomDevice()])
309309
ftypes = [Float16, Float32, Float64]
310310
cftypes = [Complex32, Complex64, Complex128, ftypes...]
311-
types = [Bool, Char, Base.BitInteger_types..., ftypes...]
311+
types = [Bool, Char, BigFloat, Base.BitInteger_types..., ftypes...]
312312
randset = Set(rand(Int, 20))
313313
randdict = Dict(zip(rand(Int,10), rand(Int, 10)))
314314
collections = [IntSet(rand(1:100, 20)) => Int,
@@ -322,6 +322,9 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
322322
Float64 => Float64,
323323
"qwèrtï" => Char,
324324
GenericString("qwèrtï") => Char]
325+
functypes = Dict(rand => types, randn => cftypes, randexp => ftypes,
326+
rand! => types, randn! => cftypes, randexp! => ftypes)
327+
325328
b2 = big(2)
326329
u3 = UInt(3)
327330
for f in [rand, randn, randexp]
@@ -330,7 +333,7 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
330333
f(rng..., 2, 3) ::Array{Float64, 2}
331334
f(rng..., b2, u3) ::Array{Float64, 2}
332335
f(rng..., (2, 3)) ::Array{Float64, 2}
333-
for T in (f === rand ? types : f === randn ? cftypes : ftypes)
336+
for T in functypes[f]
334337
a0 = f(rng..., T) ::T
335338
a1 = f(rng..., T, 5) ::Vector{T}
336339
a2 = f(rng..., T, 2, 3) ::Array{T, 2}
@@ -370,7 +373,7 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
370373
@test_throws ArgumentError rand(rng..., C, 5)
371374
end
372375
for f! in [rand!, randn!, randexp!]
373-
for T in (f! === rand! ? types : f! === randn! ? cftypes : ftypes)
376+
for T in functypes[f!]
374377
X = T == Bool ? T[0,1] : T[0,1,2]
375378
for A in (Array{T}(5), Array{T}(2, 3), GenericArray{T}(5), GenericArray{T}(2, 3))
376379
f!(rng..., A) ::typeof(A)
@@ -409,17 +412,19 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
409412
end
410413
end
411414

412-
function hist(X,n)
413-
v = zeros(Int,n)
415+
function hist(X, n)
416+
v = zeros(Int, n)
414417
for x in X
415-
v[floor(Int,x*n)+1] += 1
418+
v[floor(Int, x*n) + 1] += 1
416419
end
417420
v
418421
end
419422

420423
# test uniform distribution of floats
421-
for rng in [srand(MersenneTwister(0)), RandomDevice()]
422-
for T in [Float16,Float32,Float64]
424+
for rng in [srand(MersenneTwister(0)), RandomDevice()],
425+
T in [Float16, Float32, Float64, BigFloat],
426+
prec in (T == BigFloat ? [3, 53, 64, 100, 256, 1000] : [256])
427+
setprecision(BigFloat, prec) do
423428
# array version
424429
counts = hist(rand(rng, T, 2000), 4)
425430
@test minimum(counts) > 300 # should fail with proba < 1e-26

0 commit comments

Comments
 (0)