# Performance of generating uniform Float32 numbers

**URL:** <https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 6, 2023, 2:57pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863 "2023-11-06T14:57:37Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)\
**Post date:** [November 6, 2023, 2:57pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863/1 "2023-11-06T14:57:37Z")

</div>

I’m trying to generate `Float32`’s from a uniformly from a range, and found Normal from distributions doesn’t offer great performance compared to just stretching and shifting what `rand(Float32)` already produces. Am I doing something wrong?

```julia
mutable struct RangeFloats
   rangebegin::Float32
   rangelength::Float32
end

mutable struct RangeDistribution
   d::Uniform{Float32}
end

@inline function generate_uniform(rf::RangeFloats)
   return rand(Float32)*rf.rangelength + rf.rangebegin
end

function sampleuniform(rf::RangeFloats)
    cum = 0f0
    for _ in 1:10000
        cum += generate_uniform(rf)
    end
    return cum
end

function sampleuniform(rd::RangeDistribution)
    cum = 0f0
    for _ in 1:10000
        cum += Float32(rand(rd.d))
    end
    return cum
end

```

Here I find `sampleuniform(::RangeFloats)` has better performance.

---

<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:** [November 6, 2023, 3:54pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863/2 "2023-11-06T15:54:49Z")

</div>

> [@f.ij](#):
>
> Here I find `sampleuniform(::RangeFloats)` has better performance.

It looks like [`rand(::Uniform)` from Distributions.jl](https://github.com/JuliaStats/Distributions.jl/blob/7e232ca86c56c4b2e1e7a44b16aa23c26668af3d/src/univariate/continuous/uniform.jl#L154) is slower for two reasons:

1. It always returns a `Float64` even if the endpoints are `Float32`, which causes the random-number generation and the arithmetic to be more expensive than necessary. This explains about 2/3 of the peformance difference on my machine (as can be verified by manually implementing a `generate_uniform(u::Uniform{T}) where {T} = rand(float(real(T)))*(u.b - u.a) + u.a` method and calling that instead of `rand`). It is a known issue that was reported recently: [Inconsistent Type Behavior for Uniform Distribution · Issue #1783 · JuliaStats/Distributions.jl · GitHub](https://github.com/JuliaStats/Distributions.jl/issues/1783)

2. `Uniform` stores the endpoints [a,b), so it has to compute `b-a` on each call. This explains the remaining 1/3 of the cost difference on my machine.

---

<div class="post-metadata">

**Author:** ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)\
**Post date:** [November 6, 2023, 5:15pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863/3 "2023-11-06T17:15:08Z")

</div>

Thanks for the reply!

Yes I looked around and saw indeed that `rand(::Uniform{Float32})` returning a `Float64` has been a longstanding problem. Wouldn’t this easily be solved in the current implementation by just adding a method `rand(rng::AbstractRNG, d::Uniform{T}) where T = d.a + (d.b - d.a) * rand(rng, T)`. For the second it might be useful to either just store the length instead of the endpoint, or add an extra field that is computed on construction?

These seem like very obvious fixes to me, so I’m assuming these have been considered already. Thus I also assume the situation is a bit more complicated than I think. I’d be interested to know why this has not been ‘fixed’ yet.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [November 6, 2023, 5:43pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863/4 "2023-11-06T17:43:12Z")

</div>

The reason is almost invariably lack of time. If you feel like making a PR, I think both the additional method as well as the cache would make sense, as it could also be used in other methods. Otherwise I can give it a shot later.

---

<div class="post-metadata">

**Author:** ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)\
**Post date:** [November 6, 2023, 6:11pm UTC](https://discourse.julialang.org/t/performance-of-generating-uniform-float32-numbers/105863/5 "2023-11-06T18:11:22Z")

</div>

I made a PR [here](https://github.com/JuliaStats/Distributions.jl/pull/1796).
