Some (More) C++ PRNG Implementations
Nearly a year ago, I wrote a post suggesting some good alternatives to PCG. As part of that post, I included links to C++ implementations of those PRNGs, following C++-11 conventions (although omitting rarely-used features such as state I/O).
Since that post, I've written my own C++ implementations of a few more generation schemes. Links and brief descriptions below.
JSF: Bob Jenkins's Small/Fast Chaotic PRNG
The gist jsf.hpp
contains an implementation of Bob Jenkins's “Small/Fast PRNG”, which is based on a random invertible mapping—what some call a “chaotic PRNG”. I discussed this generator in a previous post, but the short version is that it passes stringent statistical tests, seems to be quite annoying to predict, and works well. It's also very fast.
My C++ implementation provides the standard jsf64
and jsf32
variants, as well as a number of variations Jenkins suggests that use different constants that should also work well. It also includes some tiny versions, jsf16
and jsf8
, which are mostly designed for experimental use (these smaller variants should not be expected to pass extensive statistical tests).
GJrand: David Blackman's Chaotic PRNG
The gist gjrand.hpp
contains an implementation of David Blackman's gjrand
PRNG, which is based on a random invertible mapping that includes a counter to guarantee no small cycles. I will discuss this generator in a future post, but the short version is that it passes stringent statistical tests, and works well. It's also fast, although not quite as fast as JSF, but on the other hand appears to have slightly stronger bit-mixing properties than JSF.
My C++ implementation provides the standard gjrand64
variant, and at my request Blackman also made a gjrand32
variant. It also includes some tiny versions, gjrand16
and gjrand8
, which are mostly designed for experimental use (these smaller variants should not be expected to pass extensive statistical tests).
SFC: Chris Doty-Humphrey's Chaotic PRNG
The gist sfc.hpp
contains an implementation of Chris Doty-Humphrey's sfc
PRNG, which is based on a random invertible mapping that includes a counter to guarantee no small cycles. I will discuss this generator in a future post, but the short version is that it passes stringent statistical tests, and works well. It's also very fast, although it appears to have slightly weaker bit-mixing properties than JSF or gjrand
.
My C++ implementation provides the standard sfc64
and sfc32
variants. It also includes some tiny versions, sfc16
and sfc8
, which are mostly designed for experimental use (these smaller variants should not be expected to pass extensive statistical tests).
Lehmer: A 128-Bit Lehmer PRNG
The gist lehmer.hpp
provides a C++ implementation of fast, 128-bit, Lehmer-style PRNGs (MCGs) as discussed in a previous post. On 64-bit x86 CPUs these are some of the fastest good-quality PRNGs I am aware of.
This code requires C++17 and a __uint128_t
type (supported by Clang, GCC, and Intel's compiler). It provides mcg128
and mcg128_fast
, the latter using a 64-bit multiplicative constant rather than the usual 128-bit constant for additional speed.
SplitMix: 32-Bit and 64-Bit Output from 128-Bit State
The gist splitmix.hpp
provides a C++ implementation of SplitMix, as described by Guy L. Steele, Jr., Doug Lea and Christine H. Flood in the paper Fast Splittable Pseudorandom Number Generators and implemented in Java 8 as SplittableRandom (cannonical source code).
This C++ implementation avoids the bugs present in implementations directly derived from the (erroneous) code in the SplitMix paper. Without these bugs it has all properties, good and bad, that are inherent in SplitMix's design (discussed at length in previous posts). In particular, the 64-bit–output variant, splitmix64
, may not be suitable for general-purpose use because it has the property that each number is only output once (similar to _once_insecure
PCG variants), which can be detected as a deviation from random behavior by statistical tests. The 32-bit–output variant, splitmix32
, does not have this issue.
Unlike the other implementations described in this post, this implementation includes both jump-ahead and distance operations (most implementations of SplitMix do not offer these features, although they are quite easy to provide). Also, in contrast to other implementations, the two variants are represented as separate classes (although it is possible to cast between them; splitmix32
is a subclass of splitmix64
).
Arc4: A Classic
The gist arc4.hpp
provides a C++ implementation of Arc4, based on the OpenBSD implementation (specifically the version found in Apple's Libc-594.9.4).
As a general-purpose PRNG, it is rather slow, and it is also slow by the standards of modern cryptographic PRNGs and is also considered too weak to use for cryptographic purposes. It is, however, of historical interest and can be useful in testing to see how sensitive a algorithms are to PRNG speed.
And more…
Other generators are linked to in my earlier post. I have also updated my C++ implementation of Xoroshiro to reflect the most recent changes made by Vigna & Blackman, and created a C++ implementation of their newest scheme, Xoshiro.