+
+[](https://github.com/schmouk/pyrandlib/license) [](https://github.com/schmouk/pyrandlib/releases) []() []()
+
@@ -32,7 +34,7 @@ SOFTWARE.
## Intro
-This library implements some of the best-in-class pseudo random generators as evaluated by Pierre L'Ecuyer and Richard Simard in their famous paper "TestU01: A C library for empirical testing of random number generators" (ACM Trans. Math. Softw. Vol. 33 N.4, August 2007 - see reference [1]. The reader will take benefit reading L'Ecuyer & Simard's paper. It implements also newer pseudo random generators that have been published since then. Their exhaustive list is provided here below and is valid for version 2.0 and above (i.e. since 2025/03):
+This library implements some of the best-in-class pseudo random generators as evaluated by Pierre L'Ecuyer and Richard Simard in their famous paper "TestU01: A C library for empirical testing of random number generators" (ACM Trans. Math. Softw. Vol. 33 N.4, August 2007 - see reference [1]). The reader will take benefit from reading L'Ecuyer & Simard's paper. This library implements also newer pseudo random generators that have been published since then. Their exhaustive list is provided here below and is valid for versions 2.0 and above of the library (i.e. since 2025/03):
* **Collatz-Weyl Generator** (Tomasz R. Dziala, **2023**)
(CWG, 64 bits, 128 bits or 128/64 bits, 3 different values of periodicities, see reference [8]);
@@ -58,14 +60,14 @@ Each of the Pseudo Random Numbers Generator (PRNG) implemented in **PyRandLib**
Latest version of **PyRandLib** is version **2.2**, released by October 2025.
* It provides implementations dedicated to different versions of Python: 3.6 (the original version of the library), 3.9, 3.10, 3.11, 3.12, 3.13 and 3.14.
-* Time performances of every PRNG and for each version of Python (starting at 3.9) have been evaluated and are provided in a table below - see section *CPU Performances*.
+* Time performances of every PRNG and for each version of Python (starting at 3.9) have been evaluated and are provided in tables below - see section *CPU Performances*.
* Furthermore, starting from release 2.1 **PyRandLib** is **fully validated**. PyTest and PyTest-cov are now used to unit-test the code with a full 100% code coverage.
### Why not Mersenne twister?
-The Mersenne twister PRNG proposed by Matsumoto and Nishimura - see [5] - is the most widely used one. The Random class of module random in Python implements this PRNG. It is also implemented in C++ and Java standard libraries for instance.
+The Mersenne twister PRNG proposed by Matsumoto and Nishimura - see [5] - is the most widely used PRNG. The Random class of module random in Python implements this PRNG. It is also implemented in C++ and Java standard libraries for instance.
It offers a very good period (2^19937, i.e. about 4.3e6001). Unfortunately, this PRNG is a little bit long to compute (up to 3 times than LCGs, 60% more than LFibs and a little bit less than MRGs, see below at section 'Architecture overview'). Moreover, it fails four of the hardest TestU01 tests. You can still use it as your preferred PRNG but **PyRandLib** implements many other PRNGs that are either far faster or far better in terms of generated pseudo-randomness than the Mersenne twister PRNG.
@@ -79,7 +81,7 @@ Since release **2.0** of **PyrandLib** (Mar. 2025), the root directory of the li
Since release **2.1** of **PyRandLib** (Jun. 2025), the whole code has been validated with unit tests (via *pytest* and *pytest-cov*). A few bugs have been fixed (*protected method `Pcg1024_32._externalstep()` implementation, or a typo in a shifting constant in Well19937c`.next()` for instance*). The code coverage rate is 100%. Pytest coverage output results are provided in files `coverage-res.txt`.
Release **2.0** of **PyRandLib** is nevertheless still available **but it should no more be used**.
-Release **2.2** (Oct. 2025) provides code for Python 3.14. Code is identical to the one provided for Python 3.13, with a very few optimizations on some generators code. Notice: the CPU performance tests show that Python 3.14 runs faster than Python 3.13 on same PyRandLib code.
+Release **2.2** (Oct. 2025) provides code for Python 3.14. This code is identical to the one provided for Python 3.13, with a very few optimizations on some generators implementation. Notice: the CPU performance tests show that Python 3.14 runs faster than Python 3.13 on same PyRandLib code.
**Notice**: distribution version to be installed via pip or easy-install in cmd tool or in console is still to come (no date yet, expected with release **3.0** of **PyRandLib**).
@@ -91,7 +93,7 @@ The unit tests code is available for every Python standard version (3.6, 3.9 and
### Install pytest and pytest-cov
To run the unit tests by your own, you have to install first pytest and pytest-cov in your Python environment (or virtual environment, recommended). The procedure is desribed below.
-#### In a Virtual environment
+#### Either in a Virtual environment
In a console, create a new virtual environment in a path of your choice on disk:
> python -m venv | PyRandLib class | TU01 generator name (1) | Memory Usage | Period | SmallCrush fails | Crush fails | BigCrush fails | time-64 bits | time-32bits |
|---|---|---|---|---|---|---|---|---|
| Cwg64 | *CWG64* | 8 x 4-bytes | >= 2^70 | 0 | 0 | 0 | n.a. | n.a. |
| Cwg128_64 | *CWG128-64* | 10 x 4-bytes | >= 2^71 | 0 | 0 | 0 | n.a. | n.a. |
| Cwg128 | *CWG128* | 16 x 4-bytes | >= 2^135 | 0 | 0 | 0 | n.a. | n.a. |
| FastRand32 | LCG(2^32, 69069, 1) | 1 x 4-bytes | 2^32 | 11 | 106 | *too many* | 0.67 | 3.20 |
| FastRand63 | LCG(2^63, 9219741426499971445, 1) | 2 x 4-bytes | 2^63 | 0 | 5 | 7 | 0.75 | 4.20 |
| LFib78 | LFib(2^64, 17, 5, +) | 34 x 4-bytes | 2^78 | 0 | 0 | 0 | 1.1 | n.a. |
| LFib116 | LFib(2^64, 55, 24, +) | 110 x 4-bytes | 2^116 | 0 | 0 | 0 | 1.0 | n.a. |
| LFib668 | LFib(2^64, 607, 273, +) | 1,214 x 4-bytes | 2^668 | 0 | 0 | 0 | 0.9 | n.a. |
| LFib1340 | LFib(2^64, 1279, 861, +) | 2,558 x 4-bytes | 2^1,340 | 0 | 0 | 0 | 0.9 | n.a. |
| Melg607 | *Melg607-64* | 21 x 4-bytes | 2^607 | 0 | 0 | 0 | n.a. | n.a |
| Melg19937 | *Melg19937-64* | 625 x 4-bytes | 2^19,937 | 0 | 0 | 0 | n.a. | n.a |
| Melg44497 | *Melg44497-64* | 1,392 x 4-bytes | 2^44,497 | 0 | 0 | 0 | n.a. | n.a |
| Mrg287 | Marsa-LFIB4 | 256 x 4-bytes | 2^287 | 0 | 0 | 0 | 0.8 | 3.40 |
| Mrg1457 | DX-47-3 | 47 x 4-bytes | 2^1,457 | 0 | 0 | 0 | 1.4 | n.a. |
| Mrg49507 | DX-1597-2-7 | 1,597 x 4-bytes | 2^49,507 | 0 | 0 | 0 | 1.4 | n.a. |
| Pcg64_32 | *PCG XSH RS 64/32 (LCG)* | 2 x 4 bytes | 2^64 | 0 | 0 | 0 | n.a. | n.a. |
| Pcg128_64 | *PCG XSL RR 128/64 (LCG)* | 4 x 4 bytes | 2^128 | 0 | 0 | 0 | n.a. | n.a. |
| Pcg1024_32 | *PCG XSH RS 64/32 (EXT 1024)* | 1,026 x 4 bytes | 2^32,830 | 0 | 0 | 0 | n.a. | n.a. |
| Squares32 | *squares32* | 4 x 4-bytes | 2^64 | 0 | 0 | 0 | n.a. | n.a. |
| Squares64 | *squares64* | 4 x 4-bytes | 2^64 | 0 | 0 | 0 | n.a. | n.a. |
| Well512a | not available | 16 x 4-bytes | 2^512 | n.a. | n.a. | n.a. | n.a. | n.a. |
| Well1024a | WELL1024a | 32 x 4-bytes | 2^1,024 | 0 | 4 | 4 | 1.1 | 4.0 |
| Well19937c (2) | WELL19937a | 624 x 4-bytes | 2^19,937 | 0 | 2 | 2 | 1.3 | 4.3 |
| Well44497b (3) | not available | 1,391 x 4-bytes | 2^44,497 | n.a. | n.a. | n.a. | n.a. | n.a. |
| Mersenne Twister | MT19937 | 624 x 4-bytes | 2^19,937 | 0 | 2 | 2 | 1.6 | 4.30 |
| Xoroshiro256 | *xiroshiro256*** | 16 x 4-bytes | 2^256 | 0 | 0 | 0 | 0.84 | n.a. |
| Xoroshiro512 | *xiroshiro512*** | 32 x 4-bytes | 2^512 | 0 | 0 | 0 | 0.99 | n.a. |
| Xoroshiro1024 | *xiroshiro1024*** | 64 x 4-bytes | 2^1,024 | 0 | 0 | 0 | 1.17 | n.a. |
| PyRandLib class | Python 3.9 | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 | Python 3.14 | SmallCrush fails | Crush fails | BigCrush fails |
|---|---|---|---|---|---|---|---|---|---|
| Cwg64 | 0.45 | 0.44 | 0.49 | 0.56 | 0.37 | 0.24 | *0* | *0* | *0* |
| Cwg128_64 | 0.47 | 0.46 | 0.50 | 0.59 | 0.38 | 0.26 | *0* | *0* | *0* |
| Cwg128 | 0.52 | 0.54 | 0.54 | 0.64 | 0.41 | 0.26 | *0* | *0* | *0* |
| FastRand32 | 0.15 | 0.16 | 0.14 | 0.17 | 0.11 | 0.07 | *11* | *106* | *too many* |
| FastRand63 | 0.16 | 0.17 | 0.16 | 0.18 | 0.11 | 0.08 | *0* | *5* | *7* |
| LFib78 | 0.28 | 0.29 | 0.27 | 0.32 | 0.20 | 0.11 | *0* | *0* | *0* |
| LFib116 | 0.29 | 0.29 | 0.28 | 0.32 | 0.21 | 0.11 | *0* | *0* | *0* |
| LFib668 | 0.30 | 0.30 | 0.29 | 0.34 | 0.22 | 0.12 | *0* | *0* | *0* |
| LFib1340 | 0.31 | 0.31 | 0.30 | 0.35 | 0.22 | 0.13 | *0* | *0* | *0* |
| Melg607 | 0.73 | 0.74 | 0.73 | 0.79 | 0.61 | 0.50 | *0* | *0* | *0* |
| Melg19937 | 0.76 | 0.74 | 0.76 | 0.82 | 0.60 | 0.51 | *0* | *0* | *0* |
| Melg44497 | 0.75 | 0.76 | 0.77 | 0.82 | 0.62 | 0.52 | *0* | *0* | *0* |
| Mrg287 | 0.46 | 0.48 | 0.44 | 0.51 | 0.34 | 0.21 | *0* | *0* | *0* |
| Mrg1457 | 0.43 | 0.44 | 0.41 | 0.48 | 0.32 | 0.21 | *0* | *0* | *0* |
| Mrg49507 | 0.44 | 0.45 | 0.42 | 0.48 | 0.34 | 0.24 | *0* | *0* | *0* |
| Pcg64_32 | 0.30 | 0.31 | 0.28 | 0.32 | 0.22 | 0.19 | *0* | *0* | *0* |
| Pcg128_64 | 0.45 | 0.46 | 0.44 | 0.49 | 0.34 | 0.30 | *0* | *0* | *0* |
| Pcg1024_32 | 0.58 | 0.59 | 0.54 | 0.55 | 0.39 | 0.33 | *0* | *0* | *0* |
| Squares32 | 0.83 | 0.83 | 0.82 | 0.92 | 0.67 | 0.63 | *0* | *0* | *0* |
| Squares64 | 1.02 | 1.01 | 1.01 | 1.14 | 0.86 | 0.80 | *0* | *0* | *0* |
| Well512a | 1.37 | 1.44 | 1.27 | 1.42 | 1.10 | 0.88 | *n.a.* | *n.a.* | n.a. |
| Well1024a | 1.27 | 1.31 | 1.17 | 1.29 | 1.00 | 0.83 | *0* | *4* | *4* |
| Well19937c (1) | 1.68 | 1.75 | 1.58 | 1.76 | 1.38 | 1.26 | *0* | *2* | *2* |
| Well44497b (2) | 1.91 | 1.99 | 1.80 | 2.02 | 1.63 | 1.43 | *n.a.* | *n.a.* | n.a. |
| Xoroshiro256 | 1.39 | 1.38 | 1.31 | 1.47 | 1.06 | 0.98 | *0* | *0* | *0* |
| Xoroshiro512 | 1.70 | 1.67 | 1.60 | 1.77 | 1.37 | 1.17 | *0* | *0* | *0* |
| Xoroshiro1024 | 1.63 | 1.63 | 1.52 | 1.72 | 1.26 | 1.15 | *0* | *0* | *0* |
| PyRandLib class | Python 3.9 | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 | Python 3.14 | SmallCrush fails | Crush fails | BigCrush fails |
|---|---|---|---|---|---|---|---|---|---|
| Cwg64 | 0.79 | 0.77 | 0.84 | 0.97 | 0.76 | 0.48 | *0* | *0* | *0* |
| Cwg128_64 | 0.82 | 0.80 | 0.88 | 0.99 | 0.78 | 0.49 | *0* | *0* | *0* |
| Cwg128 | 0.89 | 0.94 | 0.96 | 1.13 | 0.83 | 0.52 | *0* | *0* | *0* |
| FastRand32 | 0.27 | 0.27 | 0.26 | 0.31 | 0.21 | 0.14 | *11* | *106* | *too many* |
| FastRand63 | 0.30 | 0.29 | 0.29 | 0.35 | 0.22 | 0.15 | *0* | *5* | *7* |
| LFib78 | 0.52 | 0.49 | 0.50 | 0.56 | 0.35 | 0.21 | *0* | *0* | *0* |
| LFib116 | 0.53 | 0.51 | 0.51 | 0.57 | 0.36 | 0.22 | *0* | *0* | *0* |
| LFib668 | 0.55 | 0.52 | 0.53 | 0.60 | 0.39 | 0.24 | *0* | *0* | *0* |
| LFib1340 | 0.55 | 0.53 | 0.55 | 0.62 | 0.41 | 0.25 | *0* | *0* | *0* |
| Melg607 | 1.30 | 1.31 | 1.26 | 1.40 | 1.15 | 0.98 | *0* | *0* | *0* |
| Melg19937 | 1.37 | 1.32 | 1.31 | 1.43 | 1.14 | 0.99 | *0* | *0* | *0* |
| Melg44497 | 1.33 | 1.35 | 1.32 | 1.42 | 1.16 | 0.99 | *0* | *0* | *0* |
| Mrg287 | 0.86 | 0.84 | 0.82 | 0.91 | 0.61 | 0.37 | *0* | *0* | *0* |
| Mrg1457 | 0.81 | 0.78 | 0.76 | 0.86 | 0.61 | 0.40 | *0* | *0* | *0* |
| Mrg49507 | 0.75 | 0.69 | 0.68 | 0.86 | 0.56 | 0.49 | *0* | *0* | *0* |
| Pcg64_32 | 0.56 | 0.52 | 0.48 | 0.56 | 0.44 | 0.40 | *0* | *0* | *0* |
| Pcg128_64 | 0.80 | 0.74 | 0.73 | 0.86 | 0.63 | 0.62 | *0* | *0* | *0* |
| Pcg1024_32 | 1.08 | 1.06 | 0.95 | 0.96 | 0.75 | 0.69 | *0* | *0* | *0* |
| Squares32 | 1.48 | 1.45 | 1.40 | 1.67 | 1.31 | 1.26 | *0* | *0* | *0* |
| Squares64 | 1.83 | 1.79 | 1.71 | 2.01 | 1.62 | 1.62 | *0* | *0* | *0* |
| Well512a | 2.62 | 2.64 | 2.26 | 2.60 | 2.08 | 1.77 | *n.a.* | *n.a.* | n.a. |
| Well1024a | 2.28 | 2.36 | 1.98 | 2.24 | 1.87 | 1.60 | *0* | *4* | *4* |
| Well19937c (1) | 3.23 | 3.44 | 2.84 | 3.12 | 2.61 | 2.44 | *0* | *2* | *2* |
| Well44497b (2) | 3.66 | 3.91 | 3.18 | 3.55 | 2.92 | 2.82 | *n.a.* | *n.a.* | n.a. |
| Xoroshiro256 | 2.37 | 2.24 | 2.25 | 2.55 | 1.93 | 1.87 | *0* | *0* | *0* |
| Xoroshiro512 | 2.94 | 2.81 | 2.72 | 3.04 | 2.30 | 2.27 | *0* | *0* | *0* |
| Xoroshiro1024 | 2.78 | 2.59 | 2.41 | 3.01 | 2.06 | 2.23 | *0* | *0* | *0* |