Forked version because cannot import:
github.com/flyingmutant/rand: github.com/flyingmutant/rand@v0.2.7: parsing go.mod:
module declares its path as: pgregory.net/rand
but was required as: github.com/flyingmutant/rand
pregory.net/rand: cannot find module providing package pregory.net/rand: unrecognized import path "pregory.net/rand": https fetch: Get "https://pregory.net/rand?go-get=1": dial tcp: lookup pregory.net: no such host
This one uses import "github.com/kokizzu/rand"
, contact original creator if you have issues or patch
Fast, high quality alternative to math/rand
and golang.org/x/exp/rand
.
Compared to these packages, github.com/kokizzu/rand
:
- is API-compatible with all
*rand.Rand
methods, - is significantly faster, while improving the generator quality,
- has simpler generator initialization:
rand.New()
instead ofrand.New(rand.NewSource(time.Now().UnixNano()))
rand.New(1)
instead ofrand.New(rand.NewSource(1))
- is deliberately not providing most top-level functions like
ExpFloat64()
orInt()
and theSource
interface.
All benchmarks were run on Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
,
linux/amd64
.
Compared to math/rand:
name old time/op new time/op delta
Float64-48 180ns ± 8% 1ns ±12% -99.66% (p=0.000 n=10+9)
Intn-48 186ns ± 2% 1ns ±11% -99.63% (p=0.000 n=10+10)
Intn_Big-48 200ns ± 1% 1ns ±19% -99.28% (p=0.000 n=8+10)
Uint64-48 193ns ± 5% 1ns ± 3% -99.72% (p=0.000 n=9+9)
Rand_New 12.7µs ± 4% 0.1µs ± 6% -99.38% (p=0.000 n=10+10)
Rand_ExpFloat64 9.66ns ± 3% 5.90ns ± 3% -38.97% (p=0.000 n=10+10)
Rand_Float32 8.90ns ± 5% 2.04ns ± 4% -77.05% (p=0.000 n=10+10)
Rand_Float64 7.62ns ± 4% 2.93ns ± 3% -61.50% (p=0.000 n=10+10)
Rand_Int 7.74ns ± 3% 2.92ns ± 2% -62.30% (p=0.000 n=10+10)
Rand_Int31 7.81ns ± 3% 1.92ns ±14% -75.39% (p=0.000 n=10+10)
Rand_Int31n 12.7ns ± 3% 3.0ns ± 3% -76.66% (p=0.000 n=9+10)
Rand_Int31n_Big 12.6ns ± 4% 3.4ns ±10% -73.39% (p=0.000 n=10+10)
Rand_Int63 7.78ns ± 4% 2.96ns ± 6% -61.97% (p=0.000 n=10+9)
Rand_Int63n 26.4ns ± 1% 3.6ns ± 3% -86.56% (p=0.000 n=10+10)
Rand_Int63n_Big 26.2ns ± 7% 6.2ns ± 4% -76.53% (p=0.000 n=10+10)
Rand_Intn 14.4ns ± 5% 3.5ns ± 3% -75.72% (p=0.000 n=10+10)
Rand_Intn_Big 28.8ns ± 2% 6.0ns ± 6% -79.03% (p=0.000 n=10+10)
Rand_NormFloat64 10.7ns ± 6% 6.0ns ± 3% -44.28% (p=0.000 n=10+10)
Rand_Perm 1.34µs ± 1% 0.39µs ± 3% -70.86% (p=0.000 n=9+10)
Rand_Read 289ns ± 5% 104ns ± 5% -64.00% (p=0.000 n=10+10)
Rand_Seed 10.9µs ± 4% 0.0µs ± 6% -99.69% (p=0.000 n=10+10)
Rand_Shuffle 790ns ± 4% 374ns ± 5% -52.63% (p=0.000 n=10+10)
Rand_ShuffleOverhead 522ns ± 3% 204ns ± 4% -60.83% (p=0.000 n=10+10)
Rand_Uint32 7.82ns ± 3% 1.72ns ± 3% -77.98% (p=0.000 n=10+9)
Rand_Uint64 9.59ns ± 3% 2.83ns ± 2% -70.47% (p=0.000 n=10+9)
name old alloc/op new alloc/op delta
Rand_New 5.42kB ± 0% 0.05kB ± 0% -99.12% (p=0.000 n=10+10)
Rand_Perm 416B ± 0% 416B ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
Rand_New 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10)
Rand_Perm 1.00 ± 0% 1.00 ± 0% ~ (all equal)
name old speed new speed delta
Rand_Read 887MB/s ± 4% 2464MB/s ± 4% +177.83% (p=0.000 n=10+10)
Rand_Uint32 511MB/s ± 3% 2306MB/s ± 7% +350.86% (p=0.000 n=10+10)
Rand_Uint64 834MB/s ± 3% 2811MB/s ± 4% +236.85% (p=0.000 n=10+10)
Compared to golang.org/x/exp/rand:
name old time/op new time/op delta
Float64-48 175ns ± 8% 1ns ±12% -99.65% (p=0.000 n=10+9)
Intn-48 176ns ±10% 1ns ±11% -99.61% (p=0.000 n=10+10)
Intn_Big-48 174ns ± 1% 1ns ±19% -99.18% (p=0.000 n=9+10)
Uint64-48 157ns ± 5% 1ns ± 3% -99.66% (p=0.000 n=10+9)
Rand_New 78.8ns ± 6% 78.3ns ± 6% ~ (p=0.853 n=10+10)
Rand_ExpFloat64 8.94ns ± 6% 5.90ns ± 3% -34.00% (p=0.000 n=10+10)
Rand_Float32 9.67ns ± 5% 2.04ns ± 4% -78.89% (p=0.000 n=10+10)
Rand_Float64 8.56ns ± 5% 2.93ns ± 3% -65.74% (p=0.000 n=10+10)
Rand_Int 5.75ns ± 3% 2.92ns ± 2% -49.25% (p=0.000 n=9+10)
Rand_Int31 5.72ns ± 5% 1.92ns ±14% -66.37% (p=0.000 n=10+10)
Rand_Int31n 17.4ns ± 7% 3.0ns ± 3% -82.87% (p=0.000 n=10+10)
Rand_Int31n_Big 17.3ns ± 4% 3.4ns ±10% -80.57% (p=0.000 n=10+10)
Rand_Int63 5.77ns ± 4% 2.96ns ± 6% -48.73% (p=0.000 n=10+9)
Rand_Int63n 17.0ns ± 2% 3.6ns ± 3% -79.13% (p=0.000 n=9+10)
Rand_Int63n_Big 26.5ns ± 2% 6.2ns ± 4% -76.81% (p=0.000 n=10+10)
Rand_Intn 17.5ns ± 5% 3.5ns ± 3% -79.94% (p=0.000 n=10+10)
Rand_Intn_Big 27.5ns ± 3% 6.0ns ± 6% -78.09% (p=0.000 n=10+10)
Rand_NormFloat64 10.0ns ± 3% 6.0ns ± 3% -40.45% (p=0.000 n=10+10)
Rand_Perm 1.31µs ± 1% 0.39µs ± 3% -70.04% (p=0.000 n=10+10)
Rand_Read 334ns ± 1% 104ns ± 5% -68.88% (p=0.000 n=8+10)
Rand_Seed 5.36ns ± 2% 33.73ns ± 6% +528.91% (p=0.000 n=10+10)
Rand_Shuffle 1.22µs ± 2% 0.37µs ± 5% -69.36% (p=0.000 n=10+10)
Rand_ShuffleOverhead 907ns ± 2% 204ns ± 4% -77.45% (p=0.000 n=10+10)
Rand_Uint32 5.20ns ± 5% 1.72ns ± 3% -66.84% (p=0.000 n=10+9)
Rand_Uint64 5.14ns ± 5% 2.83ns ± 2% -44.85% (p=0.000 n=10+9)
Rand_Uint64n 17.6ns ± 3% 3.5ns ± 2% -80.32% (p=0.000 n=10+10)
Rand_Uint64n_Big 27.3ns ± 2% 6.0ns ± 7% -77.97% (p=0.000 n=10+10)
Rand_MarshalBinary 30.5ns ± 1% 3.8ns ± 4% -87.70% (p=0.000 n=8+10)
Rand_UnmarshalBinary 3.22ns ± 4% 3.71ns ± 3% +15.16% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Rand_New 48.0B ± 0% 48.0B ± 0% ~ (all equal)
Rand_Perm 416B ± 0% 416B ± 0% ~ (all equal)
Rand_MarshalBinary 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10)
Rand_UnmarshalBinary 0.00B 0.00B ~ (all equal)
name old allocs/op new allocs/op delta
Rand_New 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10)
Rand_Perm 1.00 ± 0% 1.00 ± 0% ~ (all equal)
Rand_MarshalBinary 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10)
Rand_UnmarshalBinary 0.00 0.00 ~ (all equal)
name old speed new speed delta
Rand_Read 764MB/s ± 3% 2464MB/s ± 4% +222.68% (p=0.000 n=9+10)
Rand_Uint32 770MB/s ± 5% 2306MB/s ± 7% +199.35% (p=0.000 n=10+10)
Rand_Uint64 1.56GB/s ± 5% 2.81GB/s ± 4% +80.32% (p=0.000 n=10+10)
Compared to github.com/valyala/fastrand:
Note that fastrand
does not
generate good random numbers.
name old time/op new time/op delta
Uint64-48 3.20ns ±35% 0.53ns ± 3% -83.29% (p=0.000 n=10+9)
Intn-48 1.83ns ±21% 0.69ns ±11% -62.35% (p=0.000 n=10+10)
math/rand
is both slow and not up to standards
in terms of quality (but can not be changed because of Go 1 compatibility promise).
golang.org/x/exp/rand
fixes some (but not all)
quality issues, without improving the speed,
and it seems that there is no active development happening there.
This package builds on 3 primitives: raw 64-bit generation using sfc64
, floating-point
generation using floating-point multiplication, and integer generation in range using
32.64 or 64.128 fixed-point multiplication.
The primitives selected are (as far as I am aware) about as fast as you can go without sacrificing quality. On top of that, it is mainly making sure the compiler is able to inline code, and a couple of micro-optimizations.
In Go (but not in C++ or Rust) it is a costly abstraction that provides no real value.
How often do you use a non-default Source
with math/rand
?
Dislike for global mutable state. Also, without some kind of thread-local state they are
very slow (because global state needs to be mutex-protected). If you like the
convenience of top-level functions, math/rand
is a fine choice. And if you just need
a couple of random integers and don't care about the performance, rand.New().Int()
works too.
As an exception, rand.Uint64()
,
rand.Intn()
and
rand.Float64()
are provided to ease
porting of applications relying on a global random number generator that is safe for
concurrent use.
I like it. It has withstood the test of time, with no known flaws or weaknesses despite a lot of effort and CPU-hours spent on finding them. Also, it provides guarantees about period length and distance between generators seeded with different seeds. And it is fast.
A bit slow. Otherwise, pcg64dxsm
is probably a fine choice.
Quite a bit of controversy and people finding weaknesses in variants of this design.
Did you know that xoshiro256**
, which author describes as an "all-purpose, rock-solid generator"
that "passes all tests we are aware of", fails them in seconds if you multiply the output by 57?
With 64-bit state and 64-bit output, splitmix64
outputs every 64-bit number exactly once
over its 2^64 period — in other words, the probability of generating the same number is 0.
A birthday test will quickly find
this problem.
An excellent generator if you are OK with slightly lower quality. Because its output function
(unlike splitmix
) is not a bijection, some outputs are more likely to appear than others.
You can easily observe this non-uniformity with
a birthday test.
Very fast, but relatively new and untested. Also, no guarantees about the period length.
github.com/kokizzu/rand
is preparing for stable 1.0 release. Deterministic pseudo-random
generation produces the same results on 32-bit and 64-bit architectures, both little-endian
and big-endian. After 1.0, any observable change to these results would only occur together
with a major version bump.
github.com/kokizzu/rand
is licensed under the Mozilla Public License Version 2.0.