This is a three-dimensional visualization of the output of the RANDU pseudo-random number generation algorithm invented by IBM in the 1960s. Using every three consecutive output values as a point coordinate, it will be clear that these points are only regularly distributed in the 15 planes of three-dimensional space! As a result, the results of many papers that used this algorithm at that time were unreliable.
The ideal pseudo-random number generation point is expected to be uniformly dispersed throughout the space.
The RANDU algorithm is of the linear congruence generator (LCG) class.
The advantages of LCG are simple and fast, with clear mathematical derivation, and can calculate full cycle parameters to achieve ultra-long period.
However, the disadvantage is that there is a sequence correlation between successive values, resulting in an internal lattice structure. When used to generate points in an n-dimensional space, the parameters are carefully chosen, and the points are distributed on a hyperplane in a higher-dimensional space. If you don’t choose the right parameters, you’ll cluster like RANDU in the plane of a low dimensional space.
Direct use of LCG output value cannot pass the random number statistical test,
However, adding a confounding layer to the output greatly improves the statistical quality of the output, allowing it to pass a series of random number statistical tests. This is the principle of the famous Pseudo Random Number Generator PCG algorithm — LCG+ obfuscation.
The advantages and disadvantages of nonlinear quadratic congruence (QCG) and cubic congruence (CCG) are basically the same as those of LCG.
The inverse congruence generator (ICG) has no obvious lattice structure and can easily pass the statistical test of very high dimensions. It is suitable for high-dimensional applications such as financial market data simulation.
See 5.4.3Inversive Generators
However, ICG also suffers from the long period correlation phenomenon that is common to congruence class generators. Make the generator cycle much longer than the application needs, and the long cycle related drawbacks are not an issue.
The pseudo-random number generation algorithm used by the Python Random library is “Mersenne Twister” (MT). This algorithm is widely used because of its very long period.
However, the MT algorithm cannot pass some random number statistical tests (TESTU01 suite). The internal dispersion of the algorithm is poor and 01 is not balanced. For Monte Carlo simulations that require independent random number generators, it is usually not appropriate to use multiple instances where MT differs only in seed values (and no other parameter).
I have tested and sorted out a PRNG algorithm that can pass a variety of random number statistical test suites, as follows:
algorithm | cycle |
---|---|
Quadratic Congruential Generator(QCG) | 2 ^ 256 |
Cubic Congruential Generator(CCG) | 2 ^ 256 |
Inversive Congruential Generator(ICG) | 102 * 2 ^ 256 |
PCG64_XSL_RR | 2 ^ 128 |
PCG64_DXSM | 2 ^ 128 |
LCG64_32_ext | 2 ^ 128 |
LCG128Mix_XSL_RR | 2 ^ 128 |
LCG128Mix_DXSM | 2 ^ 128 |
LCG128Mix_MURMUR3 | 2 ^ 128 |
PhiloxCounter | 4 * 2 ^ (4 * 64) |
ThreeFryCounter | 4 * 2 ^ (4 * 64) |
AESCounter | 2 ^ 128 |
ChaChaCounter | 2 ^ 128 |
SPECKCounter | 2 ^ 129 |
XSM64 | 2 ^ 128 |
EFIIX64 | 2 ^ 64 |
SplitMix64 | 2 ^ 64 |
Ran64 | 2 ^ 64 |
And then realizes the algorithm of pseudo random number generator Py containing the library source code on the lot, https://github.com/fsssosei/P…
It has been released to PyPI and can be easily installed and distributed:
pip install pure-prng
The import
from pure_prng_package import pure_prng
Very simple to use, the default PRNG algorithm is QCG
> > > seed = 170141183460469231731687303715884105727 # to write the seed value > > > prng_instance = pure_prng (seed) > > > source_random_number = prng_instance.source_random_number() >>> next(source_random_number) 65852230656997158461166665751696465914198450243194923777324019418213544382100
QCG, CCG and LCG64_32_EXT are variable period algorithms
>>> prng_instance = pure_prng(seed, new_prng_period = 2 ** 512) >>> source_random_number = prng_instance.source_random_number() >>> next(source_random_number) 837548664876987880755722812618334992276524538356482537764986430463290224246912591086561574266104831591825947994411632546 6004411700005484642554244082978452
Other PRNG algorithms are fixed period algorithms. However, there is a method in the library that allows you to set the period of the output sequence of random numbers (regardless of which PRNG algorithm generates random numbers).
> > > period = 115792089237316195423570985008687907853269984665640564039457584007913129639747 # write cycle at > > > prng_instance = pure_prng(seed) >>> rand_with_period = prng_instance.rand_with_period(period) >>> next(rand_with_period) mpz(65852230656997158461166665751696465914198450243194923777324019418213544381986)
There is also method in the library to generate random floating point numbers of arbitrary precision
>>> seed = 170141183460469231731687303715884105727 >>> prng_instance = pure_prng(seed) >>> rand_float = Prng_instance. Rand_float (100) > > > next (rand_float) MPFR (100) '0.56576176351048513846261940831522',