# What's the fastest way to fill an array with random bits without using private Random.jl internals?

**URL:** https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089
**Category:** Performance
**Created:** [January 15, 2026, 11:34pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089 "2026-01-15T23:34:26Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![npbarnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/npbarnes/32/217905_2.png) [@npbarnes](https://discourse.julialang.org/u/npbarnes)
#### Post date: [January 15, 2026, 11:34pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/1 "2026-01-15T23:34:26Z")

</div>

Suppose I have an array of type e.g. `Array{Float64}` and I want to fill it with random bits as fast as possible. Note that that’s different from filling it with random floats between 0 and 1. A straight forward way to do it is

```julia-auto
rand!(reinterpret(UInt64, a))

```

which is fine, but the fastest way I’ve found to do it is

```julia-auto
GC.@preserve a rand!(Random.UnsafeView{UInt64}(pointer(a), length(a)))

```

I’m a little torn, because I want my package to have the best performance possible, but I also want my package to be reliable without the maintenance burden that comes with using private internals.

Is it possible to get the performance of the second method using only the public interface?

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [January 16, 2026, 1:12am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/2 "2026-01-16T01:12:07Z")

</div>

Out of curiosity, why do you want that?

---

<div class="post-metadata">

### Author: ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)
#### Post date: [January 16, 2026, 1:28am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/3 "2026-01-16T01:28:28Z")

</div>

`unsafe_wrap` seems to work:

```julia-auto
julia> N = 1000; a = rand(N, N);

julia> b = reinterpret(UInt64, a);

julia> c = Random.UnsafeView{UInt64}(pointer(a), length(a));

julia> d = unsafe_wrap(Vector{UInt}, Ptr{UInt}(pointer(a)), length(a));

julia> @b rand!($b), rand!($c), rand!($d)
(979.646 μs, 412.827 μs, 412.214 μs)

```

---

<div class="post-metadata">

### Author: ![npbarnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/npbarnes/32/217905_2.png) [@npbarnes](https://discourse.julialang.org/u/npbarnes)
#### Post date: [January 16, 2026, 1:40am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/4 "2026-01-16T01:40:22Z")

</div>

I’m working on a package for the ziggurat algorithm, Ziggurats.jl. It’s the same algorithm used by `randn` and `randexp`, but Ziggurats.jl allows user specified probability density functions. Without going into too many algorithmic details, to make one sample you generate a UInt64, then do some table look ups, math, etc and 99% of the time you get a result otherwise you regenerate the UInt64 and retry. When producing values in bulk, rather than generating one UInt at a time, it can be faster to just fill the array with random bits and use those as the first UInt tried for each sample. So, in Random.jl `randn` and `randexp` have lines something like this:

```julia-auto
GC.@preserve A rand!(rng, UnsafeView{UInt64}(pointer(A), length(A)))
for i in eachindex(A)
    @inbounds A[i] = _ziggurat_rand(rng, reinterpret(UInt64, A[i]))
end

```

Where 1% of the time `_ziggurat_rand` will call itself recursively with a new UInt `_ziggurat_rand(rng, rand(UInt64))`

I could do the same thing, but I don’t want Random.jl to change the interface out from under me.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [January 16, 2026, 2:28am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/5 "2026-01-16T02:28:46Z")

</div>

> [@matthias314](#):
>
> `unsafe_wrap(Vector{UInt}, Ptr{UInt}(pointer(a)), length(a));`

Note that the aliasing `Vector` and `Memory` do contribute 2 small allocations.

```julia-auto
julia> @btime rand!(reinterpret(UInt64, $a));
  29.800 μs (0 allocations: 0 bytes)

julia> @btime GC.@preserve $a rand!(Random.UnsafeView{UInt64}(pointer($a), length($a)));
  5.400 μs (0 allocations: 0 bytes)

julia> @btime GC.@preserve $a rand!(unsafe_wrap(Vector{UInt}, Ptr{UInt}(pointer($a)), length($a)););
  5.433 μs (2 allocations: 64 bytes)

```

Wonder what the 24us overhead is for.

---

<div class="post-metadata">

### Author: ![gbaraldi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gbaraldi/32/22101_2.png) [@gbaraldi](https://discourse.julialang.org/u/gbaraldi)
#### Post date: [January 16, 2026, 2:36am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/6 "2026-01-16T02:36:39Z")

</div>

Unsafe wrapping a julia array pointer is UB and will cause segfaults

---

<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: [January 16, 2026, 11:17am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/7 "2026-01-16T11:17:50Z")

</div>

> [@gbaraldi](#):
>
> Unsafe wrapping a julia array pointer is UB and will cause segfaults

What? The only things you need to stay safe from segfaults is:

1. Only do this with bitstypes
2. Don’t forget that the unsafe\_wrap thingy doesn’t keep the underlying allocation alive. You may need to gc\_preserve the underlying thing.

> [@matthias314](#):
>
> `unsafe_wrap` seems to work:

It _seems_ to work.

A small issue is that julia aliasing rules used to say that Memory{UInt64} and Memory{Float64} are forbidden from aliasing, i.e. sharing memory.

Since you are lying to the compiler about the TBAA class of the underlying memory, the optimizer could theoretically miscompile your code.

You have a potential aliasing issue when you have two accesses to the same address through two differently typed Memory, and at least one of them is a write.

You can fix the aliasing issue by telling the compiler that you’re doing something fishy, i.e. by inserting a barrier between any two such accesses. The barrier can be emitted as

```julia-auto
julia> membarrier()=Base.llvmcall("""call void asm ";","~{memory}"()
       ret void""", Cvoid, Tuple{},)

```

This is the same kind of barrier that you need if you play games with virtual memory, like mapping the same physical memory multiple times with different virtual addresses. And the same barrier you would need in C, C++, rust.

…all that being said, I currently cannot reproduce TBAA-based optimizations.

For example

```julia-auto
julia> function foo(a::Vector{Int},b::Vector{UInt32},n)
       @inbounds for i=1:n
        a[1] += 1
        b[1] += UInt32(1)
       end
       nothing
       end

```

should run in O(1), i.e. llvm should remove the loop. But llvm fails to figure out that a and b cannot alias, and it also fails to emit a check whether they alias.

---

<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: [January 16, 2026, 6:08pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/8 "2026-01-16T18:08:16Z")

</div>

the fast path in Random dispatches via `const MutableDenseArray = Union{Base.MutableDenseArrayType{T}, UnsafeView{T}} where {T}` which misses `ReinterpretArray`

maybe that should be a trait instead and catch when `sizeof(T) == sizeof(S) && a.writable && !IsReshaped && check_ptr_indexable(a) ` ?

---

<div class="post-metadata">

### Author: ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)
#### Post date: [January 16, 2026, 6:19pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/9 "2026-01-16T18:19:38Z")

</div>

Could the generic version be improved by generating the random numbers in blocks and copying, similar to what we do for generic CRC32c in [julia/stdlib/CRC32c/src/CRC32c.jl at 4969b6a31ddd4ee3e02b2fc2a477f5875967dc7a · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/4969b6a31ddd4ee3e02b2fc2a477f5875967dc7a/stdlib/CRC32c/src/CRC32c.jl#L39-L52)

---

<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: [January 16, 2026, 6:39pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/10 "2026-01-16T18:39:51Z")

</div>

probably, but I would expect at the cost of intermediate allocations

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [January 16, 2026, 6:50pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/11 "2026-01-16T18:50:44Z")

</div>

Related package that might be useful to future readers interested in fast random sampling:

> **[GitHub - LilithHafner/AliasTables.jl: An efficient sampler for discrete random variables](https://github.com/LilithHafner/AliasTables.jl)**
>
> An efficient sampler for discrete random variables

---

<div class="post-metadata">

### Author: ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)
#### Post date: [January 16, 2026, 7:02pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/12 "2026-01-16T19:02:33Z")

</div>

If I understand [https://github.com/JuliaLang/julia/pull/53687](https://github.com/JuliaLang/julia/pull/53687) correctly, Julia doesn’t promise stability for `llvmcall` users. Also, `Random.UnsafeView` is planned to be removed in the future [re-evaluate/remove `Random.UnsafeView` · Issue #36718 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/36718)

---

<div class="post-metadata">

### Author: ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)
#### Post date: [January 20, 2026, 3:47pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/13 "2026-01-20T15:47:25Z")

</div>

> [@npbarnes](#):
>
> Without going into too many algorithmic details, to make one sample you generate a UInt64, then do some table look ups, math, etc and 99% of the time you get a result otherwise you regenerate the UInt64 and retry

This reminds me of some stuff I was looking at a few years ago [as part of a discussion on the distribution of `rand`](https://discourse.julialang.org/t/output-distribution-of-rand-float32-and-rand-float64-thread-2/105184/435). In that version, I would SIMD-compute a batch of values at a time, then refine any of them that needed further work (but still in parallel, using a mask to prevent overwriting finalized values). So I did everything in one pass rather than two and entirely with SIMD.

The thing `Random.jl` is missing to make that nice is a fast function for generating a block (i.e., tuple) of random bits (which should use an immutable version of the random state to avoid frequent memory writebacks). There’s space for an internal (and maybe eventually public) function to do this. Ideally, a lot of the existing vectorized random generators would change to use it as well (they already do this, but inline in a way that’s difficult to use generically).

Think about what such an interface would need to do to support your use case. Such an interface might be worth adding eventually.

---

<div class="post-metadata">

### Author: ![npbarnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/npbarnes/32/217905_2.png) [@npbarnes](https://discourse.julialang.org/u/npbarnes)
#### Post date: [January 21, 2026, 7:10am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/14 "2026-01-21T07:10:58Z")

</div>

I don’t know enough to comment on all that.

However, right now, for my use case, I don’t think there’s any need for a new implementation or a new function or a new interface. There already is a pretty fast way to fill an array with random bits. `rand!(::Array{UInt64})` is fast. My problem is that `rand!(reinterpret(UInt64, ::Array{Float64}))` is slow. The workaround is `GC.@preserve a rand!(Random.UnsafeView{UInt64}(pointer(a), length(a)))` which is exactly as fast as `rand!(::Array{UInt64})`, BUT it uses private internals.

So if a new interface or new code is faster, then that would be great, but really what I want right now is for `rand!(reinterpret(UInt64, ::Array{Float64}))` to dispatch to the fast code that already exists in Random.jl. Earlier in the thread @adienes said something similar. Maybe they’re on to something?

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [January 21, 2026, 7:32am UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/15 "2026-01-21T07:32:06Z")

</div>

Can you do it the other way around, making use of the fast method on `Array{UInt64}` and reinterpreting to floating point afterwards?

---

<div class="post-metadata">

### Author: ![npbarnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/npbarnes/32/217905_2.png) [@npbarnes](https://discourse.julialang.org/u/npbarnes)
#### Post date: [January 21, 2026, 6:57pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/16 "2026-01-21T18:57:16Z")

</div>

That’s genius, I love it. If I was making an application or standalone simulation or something like that, I might try it, but Ziggurats.jl is a library, not an application. So the array in question is provided either to the user or by the user. It’s supposed to go something like this

```julia-auto
using Ziggurats, Random
z = ziggurat(...)
rand(z, 10^6)
# Or
a = Vector{Float64}(undef, 10^6)
rand!(a, z)

```

If I did what you suggest, in the first case I would have to return a ReinterpretArray, and in the second case I’d have to ask the user to provide a Vector{UInt64} and return a ReinterpretArray that aliases that same memory. Either way, it’s a leaky abstraction.

---

<div class="post-metadata">

### Author: ![gbaraldi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gbaraldi/32/22101_2.png) [@gbaraldi](https://discourse.julialang.org/u/gbaraldi)
#### Post date: [January 21, 2026, 6:59pm UTC](https://discourse.julialang.org/t/whats-the-fastest-way-to-fill-an-array-with-random-bits-without-using-private-random-jl-internals/135089/17 "2026-01-21T18:59:25Z")

</div>

We might be missing a specialized implementation over reinterpret arrays. Because in theory it could work just fine. Something like random bits that accepts a ReinterpretArray of UIntx
