# Output distribution of rand(Float32) and rand(Float64), thread 2

**URL:** <https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184>\
**Category:** Internals & Design\
**Tags:** float, random\
**Created:** [October 19, 2023, 1:10pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184 "2023-10-19T13:10:07Z")\
**Posts on this page:** 20\
**Page:** 17

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [October 31, 2023, 9:13pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/323 "2023-10-31T21:13:26Z")

</div>

> [@dlakelan](#):
>
> what I don’t think is ideal is if a physics grad student has to deal with running his particle simulation for a weekend and it’s _virtually guaranteed_ to give Inf as the ensemble average

I’m only mildly worried about that case – you’re going to get `Inf` within milliseconds of `rand(Float32)` invocations.

I am much more worried about:

1. The grad student who uses your `randno0(Float32)`, applies a singular inverse cdf or something like it, gets silently subtly wrong tail statistics and unwittingly pollutes the scientific literature (edit: or loses a year of their phd chasing wild geese, your pick what’s worse).
2. The grad student who uses `rand(Float64)`, dutifully tests this on their laptop over the weekend, dutifully applies for and obtains a rare spot on their local cluster, and not-so-promptly blows up with an `Inf`. `2^52` might look like a large number, but that’s a mere teraflop-hour. I feel old now, what a preposterous combination of words “mere teraflop-hour” (of course most time will be spent doing useful stuff, not generating random numbers; if you assume that RNG takes 0.1% of the compute time, then you blow up in 1k teraflop-hours which I think is a less preposterous amount of compute that we old-timers like to believe…)

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [October 31, 2023, 9:20pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/324 "2023-10-31T21:20:16Z")

</div>

We could also simplify this by choosing to let the “bits gradually run out” — instead of using loops, just hard code maybe three or four _highly unlikely_ nested branches of the thing. It’ll be easier to prove correct that way — and we don’t need to worry about counting the bits when we get close to rounding to zero (which will never happen anyway!).

Here’s a table of interesting values of N (using my usual assumption of worst-case bit usage with N bits), showing at what point values of p are densely sampled — or, in other words, the regions of [0, 1) which have a perfectly accurate \text{cdf} for all representable values.

| N | P(= 0) | Float16 | Float32 | Float64 |
| --- | --- | --- | --- | --- |
| 11 | 0.00049 | p ≥ 0.5 | - | - |
| 24 | 5.96e-08 | p ≥ Float16(6.104e-5) | p ≥ 0.5 | - |
| 32 | 2.33e-10 | p ≥ 0 | p ≥ 0.001953125f0 | - |
| 53 | 1.11e-16 | | p ≥ 9.313226f-10 | p ≥ 0.5 |
| 64 | 5.42e-20 | | p ≥ 4.5474735f-13 | p ≥ 0.000244140625 |
| 126 | 1.18e-38 | | p ≥ 9.8607613f-32 | p ≥ 5.293955920339377e-23 |
| 128 | 2.94e-39 | | p ≥ 2.4651903f-32 | p ≥ 1.3234889800848443e-23 |
| 149 | 1.4e-45 | | p ≥ 0 | p ≥ 6.310887241768095e-30 |
| 196 | 9.96e-60 | | | p ≥ 4.484155085839415e-44 |
| 256 | 8.64e-78 | | | p ≥ 8.636168555094445e-78 |
| 1022 | 2.23e-308 | | | p ≥ 1.0020841800044864e-292 |
| 1074 | 5.0e-324 | | | p ≥ 0 |

We can’t know how folks will (ab)use `rand()` but we can get `rand()` itself right. And then we can give appropriate guidance on how to use it.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [October 31, 2023, 9:57pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/325 "2023-10-31T21:57:45Z")

</div>

> [@foobar\_lv2](#):
>
> `Inf` within milliseconds of `rand(Float32)` invocations.

With the current generator within about 4 billion floats so about 16 seconds on a single core. But with an ideal Float32 you’d never get it even on your teraflop cluster for millions of years.

Similarly on an ideal Float64 generator you’d also never get it even more so.

We don’t need perfection but I’d argue based on the table Matt made we need N = 128 at a minimum to avoid observing real deviations in the cdf for small probability events with big clusters

Of course we don’t need to generate 128 each generation, we just need that resolution in the left tail. rand32\_for offered that and only generated more than 32 bits once in 4 billion numbers.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [October 31, 2023, 10:03pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/326 "2023-10-31T22:03:08Z")

</div>

> [@dlakelan](#):
>
> With the current generator within about 4 billion floats so about 16 seconds on a single core. But with an ideal Float32 you’d never get it even on your teraflop cluster for millions of years.

```julia
julia> foo() = while rand(Float32)!= 0 end 
foo (generic function with 1 method)
julia> @benchmark foo()
BenchmarkTools.Trial: 269 samples with 1 evaluation.
 Range (min … max): 44.633 μs … 108.039 ms ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 13.281 ms ┊ GC (median): 0.00%
 Time (mean ± σ): 18.660 ms ± 17.791 ms ┊ GC (mean ± σ): 0.00% ± 0.00%

  █▅▅▃▃▆▆▁▆ ▂                                       
  ███████████▇▇█▇▇▆▅█▃▇▆█▅▄▄▅▆▄▅▅▃▃▁▁▄▃▄▁▁▄▄▁▁▃▃▃▁▁▃▁▃▃▄▄▁▁▁▃▃ ▄
  44.6 μs Histogram: frequency by time 74.3 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [October 31, 2023, 10:08pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/327 "2023-10-31T22:08:11Z")

</div>

Hunh, am I not understanding what rand(Float32) is doing or am I being too cavalier about an estimate of the time it should take?

I’m imagining

```julia
function rand(Float32) 
   i = rand(UInt32)
   return ldexp(Float32(i),-32)
end

```

That should return 0 on avg every 4 billion generations right?

Note, I guess the time should be geometrically distributed… So my estimate is very coarse still I’d expect hundreds of milliseconds or a second or something

```julia

julia> function randdan()
              i = rand(UInt32)
              return ldexp(Float32(i),-32)
              end
randdan (generic function with 1 method)

julia> foo() = while randdan() != 0 end
foo (generic function with 1 method)

julia> using BenchmarkTools

julia> @benchmark(foo())
BenchmarkTools.Trial: 1 sample with 1 evaluation.
 Single result which took 28.241 s (0.00% GC) to evaluate,
 with a memory estimate of 0 bytes, over 0 allocations.

```

Ok, so looking into it in share/julia/stdlib/v1.9/Random/src/generation.jl we have:

```julia
rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float32}}) =
    reinterpret(Float32, rand(r, UInt23()) | 0x3f800000) - 1

```

So I guess it’s worse than I thought.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [November 1, 2023, 12:51am UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/328 "2023-11-01T00:51:42Z")

</div>

> [@dlakelan](#):
>
> Ok, so looking into it in share/julia/stdlib/v1.9/Random/src/generation.jl we have:
> 
> ```julia
> rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float32}}) =
> reinterpret(Float32, rand(r, UInt23()) | 0x3f800000) - 1
> 
> ```

That’s the fallback code for RNGs that only implement the minimal interface. The relevant code for the default Xoshiro RNG is here: [https://github.com/JuliaLang/julia/blob/2b73a1d6c64258fdbfa3d44cc2604e841b666120/stdlib/Random/src/Xoshiro.jl#L299-L300](https://github.com/JuliaLang/julia/blob/2b73a1d6c64258fdbfa3d44cc2604e841b666120/stdlib/Random/src/Xoshiro.jl#L299-L300). It looks like this:

```julia
rand(r::Union{TaskLocalRNG, Xoshiro}, ::SamplerTrivial{CloseOpen01{Float32}}) =
    Float32(rand(r, UInt32) >>> 8) * Float32(0x1.0p-24)

```

It throws away 8 bits of a UInt32 such that every value of the remaining 24 maps exactly to one Float32 without rounding.

---

<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 1, 2023, 3:47pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/329 "2023-11-01T15:47:50Z")

</div>

> [@dlakelan](#):
>
> what I don’t think is ideal is if a physics grad student has to deal with running his particle simulation for a weekend and it’s _virtually guaranteed_ to give Inf as the ensemble average because there’s about a 1e-9 probability to get exactly 0.0f in a calculation where 0.0 makes no sense such as a potential energy calculation and multiple billions of random numbers will be calculated (this is a weekend project for grad students these days).

These kinds of arguments that `0.0` is uniquely “dangerous” make no sense to me. If you are doing an integral (or using a cdf) with a singularity in the domain, or at the edge of the domain, you need to be careful, no matter what method you are using.

If the student uses the trapezoidal rule to do their \int\_0^1 with a singularity at 0, they will also get `Inf` — is that a bug in the trapezoidal rule? Even if they use something like QuadGK that in principle [handles (integrable) endpoint singularities](https://juliamath.github.io/QuadGK.jl/stable/quadgk-examples/#Integrands-with-singularities-and-discontinuities), they might get a failure if they request too low of an error tolerance, because singularities degrade the convergence rate (if they are not taken into account analytically).

Besides, you can have a singularity _anywhere_ — if someone tries to integrate f(x) / \sqrt{|x - 0.25|} for x \in [0,1] by a Monte–Carlo method, they will get `Inf` if `x = rand()` ever returns `x == 0.25`. Should we therefore say that `rand()` should never return the “dangerous” value of `0.25`?

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 1, 2023, 4:00pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/330 "2023-11-01T16:00:13Z")

</div>

[Phew… I was beginning to think this thread will die out 😛]

This `0.0` issue is idiosyncratic and controversial enough to make a poll interesting:

_Poll ([view on site](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/330))_

I’m putting my vote in.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 4:12pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/331 "2023-11-01T16:12:22Z")

</div>

I think the argument comes down to how often people make the assumption that the left tail of [0,1) should have some detail to it. I think as an empirical question, this is probably a pretty common assumption. People _put_ singularities near 0 specifically because they want to transform stuff near zero to stuff “near” infinity. It comes down to a question of frequency in real world code. We’ve already seen Julia had this kind of stuff in sampling exponentials (since bugfixed). People do `if (rand() < epsilon)` all the time, even if they should do `if rand(Bernoulli(eps))` also Floating point numbers behave differently near 0 than they do near 0.25 or 1.

`eps(.25f0) ~ 2.98e-8` whereas `eps(0.0f0) ~ 1.0f-45`

That we can represent small numbers near 0 could lead people to think that they should expect such numbers to come out of rand(Float32) currently though the smallest nonzero rand(Float32) is about ldexp(1.0,-24) or about 6e-8

As far as the poll, I voted that it _can_ output 0.0 but I still think it should do so with very small frequency, like ldexp(1.0f0,-64) or less

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 1, 2023, 4:21pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/332 "2023-11-01T16:21:06Z")

</div>

But,

> [@dlakelan](#):
>
> if (rand() \< epsilon)

is a bug since `rand(Bernoulli(epsilon))` uses `<=`, equality included (it is one character more, but something must be decided).

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 4:21pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/333 "2023-11-01T16:21:54Z")

</div>

Ok, here’s another poll

# Must rand() and rand!() produce the same float distribution?

_Poll ([view on site](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/333))_

Obviously I don’t know how to set up polls, please choose ONE option.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 4:27pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/334 "2023-11-01T16:27:33Z")

</div>

> [@Dan](#):
>
> is a bug since `rand(Bernoulli(epsilon))` uses `<=`,

suppose you do rand(Float32) \< ldexp(Float32(pi),-18). I don’t think this is one of the possible outputs of rand() so we’re in the case where the cdf goes above the diagonal, so we’re going to get this occurring at the wrong frequency. The frequency is going to be off by on the order of 5.96e-8 which is a relative error of about .005 Is this also a “bug”?

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 1, 2023, 4:39pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/335 "2023-11-01T16:39:31Z")

</div>

> [@dlakelan](#):
>
> also a “bug”?

As noted in a popular post earlier, we don’t expect crypto level of accuracy, just a general performance. But the `0.0` _is_ different from a pole at 0.25, because `rand()` has a natural probability interpretation, and a run-time calculated probability of `0.0` or `1.0` will usually correspond to high level of certainty (it could appear in a `p = clamp(calc_p, 0.0, 1.0)` expression. If subsequently, `rand(Bernoulli(p))` is calculated, one might reasonably expect it to return `false` on a `0.0` `p` always.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 4:41pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/336 "2023-11-01T16:41:28Z")

</div>

> [@Dan](#):
>
> If subsequently, `rand(Bernoulli, p)` is calculated, one might reasonably expect it to return `false` on a `0.0` `p` always.

good point! rand(Bernoulli(0.0f0)) should ALWAYS return false! I think the \<= test should not be used in Bernoulli

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [November 1, 2023, 4:57pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/337 "2023-11-01T16:57:41Z")

</div>

See [Output distribution of rand(Float32) and rand(Float64), thread 2 - #143 by StefanKarpinski](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/143#interlude-are-we-checking-the-uniformity-of-the-distribution-the-right-way-1) and [Output distribution of rand(Float32) and rand(Float64), thread 2 - #147 by mbauman](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/147) for more on when it’s appropriate to use `<` vs `<=`.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 1, 2023, 5:18pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/338 "2023-11-01T17:18:52Z")

</div>

From:

> [@mbauman](#):
>
> See [Output distribution of rand(Float32) and rand(Float64), thread 2 - #143 by StefanKarpinski](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/143#interlude-are-we-checking-the-uniformity-of-the-distribution-the-right-way-1)

> if you’re sampling from `(0, 1)` then I’m not sure what you  
> should do.

So not much help regarding `rand(Bernoulli(p))` problem. Although, `rand(Bernoulli())` uses Float64 IIRC and `0.0` is a more remote possibility.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [November 1, 2023, 5:27pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/339 "2023-11-01T17:27:55Z")

</div>

I suspect the only thing that will help this thread come to a productive end is to consolidate the proposed algorithms and detail for each

1. the bits of randomness
2. the support (e.g. does it include `0`, does it include every representable float)
3. for both the domain (representable floats) vs (real interval `[0,1]`)
  - the maximum difference between ideal `cdf` and empirical `cdf`
  - mean abs difference between ideal and empirical
  - uniformity of diff between ideal and empirical
  - “staircase graph” of empirical cdf

4. performance concerns (i.e. is it branchy, loopy, simdable)

otherwise there will be another 100 posts on whether or not `log(rand())` is a user mistake or not

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 6:00pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/340 "2023-11-01T18:00:21Z")

</div>

More and more I’m beginning to like this convolution style of random number generation:

```julia
function float32conv()
    r = 2.0f0
    while r < 0.0f0 || r >= 1.0
        i = rand(UInt64)
        a = i >>> 32
        b = i & (1<<32 - 1)
        r = ldexp(Float32(a),-32) + ldexp(Float32(b),-32-15) - ldexp(1.0f0,-16)
    end
    r
end

```

This convolution distribution smooths out the “stairs” in the CDF throughout the range. I’m investigating why it seems to have a slight bias below the line in this region. I’m guessing it’s because of the nature of floating addition and roundoff… not sure.

Here is the ECDF for 5000 samples less than 1e-6, for rand(Float32) (staircase) and the convolution distribution (smooth blue) as well as the ideal line (green)

 ![image](https://global.discourse-cdn.com/julialang/original/3X/e/3/e3a69d69b88c931c030141f4f6559925df3430f7.png)

I think people are going to act like rand() produces something with a smooth cdf like this, not a staircase, because this is the mathematical model they have in their head, and they know that Float32 can represent it to the accuracy shown here.

EDIT: yes, by putting in some parentheses I can eliminate that bias:

```julia

function float32conv()
    r = 2.0f0
    while r < 0.0f0 || r >= 1.0
        i = rand(UInt64)
        a = i >>> 32
        b = i & (1<<32 - 1)
        r = ldexp(Float32(a),-32) + (ldexp(Float32(b),-32-15) - ldexp(1.0f0,-16))
    end
    r
end

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/4/c4450bd7fbbc8269d1a2e6209813d2cf964a3017.png)

Investigating further, the bias seems to persist by moving farther up the CDF… I’ll look into that more, I think it has to do with asymmetry of resolution in Float32 near 0 vs near 1… should be fixable.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 1, 2023, 7:09pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/341 "2023-11-01T19:09:09Z")

</div>

Just needed to draw the diagram and be careful about where the uniform region is… this seems to fix the bias:

```julia
function float32conv()
    r = 2.0f0
    while r < 0.0f0 || r >= 1.0
        i = rand(UInt64)
        a = (i >>> 32) % UInt32
        b = reinterpret(Int32,i % UInt32)
        r = (ldexp(Float32(a),-32) + (ldexp(Float32(b),-31-15) - ldexp(1.0f0,-15)))/(1.0f0 - ldexp(1.0f0,-14))
    end
    r
end

```

It takes about 2x the time of our rand() but about 1.62 times the time of ldexp(Float32(rand(UInt32)),-32)

The smallest nonzero value this can produce is on the order of ldexp(1.0f0,-32-15) ~ 7e-15 and the cdf is obviously DRAMATICALLY better in the region below 1e-7

Here’s the region below 1e-6

 ![image](https://global.discourse-cdn.com/julialang/original/3X/3/8/384969b898b1f26793ef0baeb9fe46a898f2d18f.png)

Here’s the region below 1e-3

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/e/ae51aa2516ccb36e16399b1ec545637d7afb426f.png)

and the whole [0,1) region:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/9/a9e323b634052465b4fe05b24833e6ff581443e3.png)

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 1, 2023, 7:12pm UTC](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/342 "2023-11-01T19:12:54Z")

</div>

> [@dlakelan](#):
>
> and the whole [0,1) region:

Can you do a log-log plot?

[Previous page](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184.md?page=16)

[Next page](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184.md?page=18)
