Ultra Fast Random Number Generator for 8, 16, and 32-Bit Devices
From a post Ultra Fast Pseudorandom number generator for 8-bit by EternityForest (Dec 31, 2011) with additional edits by jeblad (Nov 20, 2025).
This is a small pseudorandom number generator (PRNG), experimentally verified to have at least a 50 million byte period for 8 bits by generating 50 million bytes and observing that there were no overlapping sequences and repeats. It passes serial correlation, entropy, Monte Carlo Pi value, arithmetic mean, and many other statistical tests. It may have a period of up to 2³², but this has not been verified.
In this specific implementation the values for the state variables are bound during instantiation of the template, thus making it possible to create repeatable sequences.
This generator is not suitable for cryptography due to its short period (by cryptographic standards) and simple construction. No attempt has been made to make this generator suitable for cryptographic use.
Due to the use of a constant counter, the generator should be resistant to latching up. A significant performance gain is had in that the x variable is only ever incremented.
Only 4 bytes of ram (in 8 bit mode) are needed for the internal state, and generating a result requires 3 XORs, 2 ADDs, one bit shift right, and one increment. Difficult or slow operations like multiply, etc., were avoided for maximum speed on ultra low power devices.
It is most useful when you need a pseudo random sequence that can be repeated for subsequent runs, and when the rather limited period is not an issue.
The prng-ultrafast library is in a single header file. Simply grab the file and put it wherever it is needed, or pull the repo as a submodule.
wget https://raw.githubusercontent.com/jeblad/prng-ultrafast/refs/heads/main/prng-ultrafast.hor
git submodule add [email protected]:jeblad/prng-ultrafast.git path-to-submoduleThe path-to-submodule would typically be something like include/prng-ultrafast if you're in the project folder.
If you're adding the prng-ultrafast as a submodule, then pull an updated version.
The most common use is to set the library up to generate a byte sized random value
#include "prng-ultrafast.h"
// initialized with default state values
prng::UltraFast<uint8_t> rand{};
// draw a new pseudo random value
uint8_t result = rand.draw();It might start with explicitly set state when instantiated
#include "prng-ultrafast.h"
// initialized with explicit state values
prng::UltraFast<uint8_t, 239U, 241U, 251U> rand{};
// draw a new pseudo random value
uint8_t result = rand.draw();Note that it must be instantiated with different state values to generate unique sequences.
Or it can be given an initial seed, a new seed, or a complete state
#include "prng-ultrafast.h"
// initialized with default state values
prng::UltraFast<uint8_t> rand{};
// make a draw
rand.draw();
// set new seed
rand.seed(42, 251U, 239U, 241U);
// draw a new pseudo random value
uint8_t result = rand.draw();It is also possible to add more entropy during initialization
#include "prng-ultrafast.h"
// initialized with additional entropy
prng::UltraFast<uint32_t> rand{1234567};
// draw a new pseudo random value
uint8_t result = rand.draw();And it is possible to add more entropy during use
#include "prng-ultrafast.h"
// initialized with default state values
prng::UltraFast<uint8_t> rand{};
// make a draw
rand.draw();
// add entropy
rand.addEntropy(1234567);
// draw a new pseudo random value
uint8_t result = rand.draw();The testing library doctest is used during development, but it isn't part of the library as such. It is although necessary for running the tests. Likewise, the implementation in prng-ultrafast-test.cpp isn't necessary for non-development use, it is only used during tests.
The doctest library is in a single header file. Simply grab the file and put it wherever it is needed, or pull the repo as a submodule.
wget https://raw.githubusercontent.com/doctest/doctest/refs/heads/master/doctest/doctest.hor
git submodule add [email protected]:doctest/doctest.git path-to-submoduleThe path-to-submodule would typically be something like include/doctest if you're in the project folder.
If you're adding the doctest as a submodule, then pull an updated version.
The usual development cycle is to compile the test file, and then run it
# when doctest.h residews in ./include
g++ -Wall -Wextra -Werror -std=c++20 -I ./include -I ./src -o prng-ultrafast-test test/prng-ultrafast-test.cpp
# when doctest.h residews in an module in ./include
g++ -Wall -Wextra -Werror -std=c++20 -I ./include/doctest/doctest -I ./src -o prng-ultrafast-test test/prng-ultrafast-test.cppThen run the executable prng-ultrafast-test that has the actual tests.
./prng-ultrafast-testThe executable can take several arguments. Check the doctest manual for examples.