# Best way to get a vector of BigFloat values drawn from a uniform distribution

**URL:** <https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256>\
**Category:** General Usage\
**Tags:** bigfloat, random\
**Created:** [April 8, 2023, 7:57pm UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256 "2023-04-08T19:57:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [April 8, 2023, 7:57pm UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256/1 "2023-04-08T19:57:53Z")

</div>

Is there some better and simple way to implement this for `BigFloat`:

```julia
function rand_uniform(lo::F, hi::F, n::Signed) where {F <: AbstractFloat}
  ret = Vector{F}(undef, n)
  dist = Distributions.Uniform(lo, hi)
  for i ∈ eachindex(ret)
    ret[i] = rand(dist)
  end
  ret
end

```

This approach fails because of a `Distributions` [bug](https://github.com/JuliaStats/Distributions.jl/issues/1252), it returns `Vector{Float64}` instead of `Vector{BigFloat}` even though `lo` and `hi` are `BigFloat`:

```julia
rand(Distributions.Uniform(lo, hi), n)

```

This, on the other hand, fails with a stack overflow because of recursion, for some reason:

```julia
rand!(zeros(F, n), Distributions.Uniform(lo, hi))

```

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [April 8, 2023, 8:27pm UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256/2 "2023-04-08T20:27:58Z")

</div>

If you only need uniformly distributed numbers, than it might be as simple as

```julia
rand_uniform(lo::T, hi::T, n) where {T <: AbstractFloat} = (hi - lo) * rand(T, n) .+ lo

```

Example result:

```julia
julia> rand_uniform(big(2.0), big(3.0), 10)
10-element Vector{BigFloat}:
 2.9174284555376025201145330738918913272402954502191116535401251098289736926065
 2.19631750020517507697116801083470708819543746756621169816997226270517883434895
 2.436503101481603637612779871925157875792727427507907758741273987186075483228166
 2.252714788297513525073447778551048335730249363760619306742365774731777906788439
 2.30163769835545213520563708849814348263120048796123561822508355898440209243495
 2.11121906581318486235373868765400026140501833929437774286345600289310872262491
 2.608123684200581891039323989360851860777985059179252353217119384669158234991661
 2.148349095950641373356503905512936681549144318191796575473727217069682413323919
 2.085010092947450646897480351115790914412328410397893567808432852935416907217017
 2.909521362406743263806281684702704618299470210785351171484376026730330458982956

```

Edit: The code assumes that `rand(T, n)` returns numbers between 0 and 1, so it only works for floating-point inputs.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 8, 2023, 11:46pm UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256/3 "2023-04-08T23:46:17Z")

</div>

Why not just use the built-in `rand` function?

```julia
rand_uniform(lo::F, hi::F, n::Integer) where {F <: AbstractFloat} =
    [rand(F) * (hi - lo) + lo for _=1:n]

```

(I used a comprehension, unlike @barucden’s solution, to avoid allocating extra temporary arrays.)

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [April 9, 2023, 8:50am UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256/4 "2023-04-09T08:50:43Z")

</div>

> [@stevengj](#):
>
> to avoid allocating extra temporary arrays

Out of curiosity, I wanted to see how big of a difference this makes. I am observing the opposite effect though!

```julia
julia> using BenchmarkTools

julia> rand_uniform1(lo::F, hi::F, n::Integer) where {F <: AbstractFloat} =
           [rand(F) * (hi - lo) + lo for _=1:n]
rand_uniform1 (generic function with 1 method)

julia> rand_uniform2(lo::T, hi::T, n) where {T <: AbstractFloat} = (hi - lo) * rand(T, n) .+ lo
rand_uniform2 (generic function with 1 method)

julia> @btime rand_uniform1(big(1.0), big(10.0), 1000);
  464.910 μs (9005 allocations: 508.14 KiB)

julia> @btime rand_uniform2(big(1.0), big(10.0), 1000);
  337.539 μs (6010 allocations: 328.90 KiB)

julia> @btime rand_uniform1(big(1.0), big(10.0), 10000);
  4.763 ms (90006 allocations: 4.96 MiB)

julia> @btime rand_uniform2(big(1.0), big(10.0), 10000);
  3.481 ms (60013 allocations: 3.20 MiB)

```

The version with a temporary array is faster and allocates less. Why is that?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [April 9, 2023, 10:36am UTC](https://discourse.julialang.org/t/best-way-to-get-a-vector-of-bigfloat-values-drawn-from-a-uniform-distribution/97256/5 "2023-04-09T10:36:53Z")

</div>

Yeah, this is getting interesting. Both your and Steven’s function’s presented some opportunities for further optimization:

```julia
function rand_uniform_nsajko(lo::F, hi::F, n::Signed) where {F <: AbstractFloat}
  ret = Vector{F}(undef, n)
  dist = Distributions.Uniform(lo, hi)
  for i ∈ eachindex(ret)
    ret[i] = rand(dist)
  end
  ret
end

rand_uniform_barucden(lo::T, hi::T, n) where {T <: AbstractFloat} =
  (hi - lo) * rand(T, n) .+ lo

rand_uniform_barucden_opt(lo::T, hi::T, n) where {T <: AbstractFloat} =
  (hi - lo) .* rand(T, n) .+ lo

rand_uniform_stevengj(lo::F, hi::F, n::Integer) where {F <: AbstractFloat} =
  [rand(F) * (hi - lo) + lo for _=1:n]

rand_uniform_stevengj_opt(lo::F, hi::F, n::Integer) where {F <: AbstractFloat} =
  let d = hi - lo
    [rand(F) * d + lo for _=1:n]
  end

# Almost as fast as rand_uniform_barucden_opt
rand_uniform_map(lo::F, hi::F, n::Signed) where {F <: AbstractFloat} =
  let v = rand(F, n)
    map!(
      let d = hi - lo, l = lo
        x -> x*d + l
      end,
      v,
      v,
    )
  end

```

The [optimized](https://docs.julialang.org/en/v1/manual/performance-tips/#More-dots:-Fuse-vectorized-operations) version of your function, `rand_uniform_barucden_opt`, seems to be the fastest of all. I _guess_ this could be because your approach uses `rand(::Type, ::Int)`, which _could_ be specially optimized in the Julia stdlib.
