这是 20 世纪 60 年代 IBM 创造的 RANDU 伪随机数生成算法的输入值作三维可视化的样子。用每三个间断输入值为一个点坐标,会分明看到,这些点只规定的散布在三维空间中的 15 个立体上!导致那期间很多用到此算法的论文论断都不牢靠。
现实的伪随机数生成点预期应该是平均弥散在整个空间中。
RANDU 算法是线性同余生成器(LCG)一类的。
LCG 长处是简洁疾速,有清晰的数学推导,可计算实现超长周期的满周期参数。
然而,毛病是有间断值之间的序列相关性,造成外在晶格构造。当用于生成 n 维空间中的点,参数精心抉择切当,点就会散布在高维空间的超平面上。参数抉择不当,就会像 RANDU 那样在低维空间的立体上就汇集了。
间接用 LCG 的输入值是无奈通过重重随机数统计测验的,
然而,给输入加个混同层,就大大改善了输入的统计品质,能够通过一系列随机数统计测验。这就是驰名伪随机数生成器 PCG 算法的原理——LCG+ 混同。
非线性的二次同余(QCG)、三次同余(CCG)优缺点根本和 LCG 统一。
逆同余生成器(ICG)是没有显著晶格构造的,能够间接轻易通过很高维度的统计测验。很适宜于金融市场数据模仿等这些高维利用。
见 5.4.3 Inversive Generators
然而,ICG 也存在同余类生成器都有的长周期相干景象这个问题。让生成器周期远大于利用须要的周期,长周期相干毛病就不是问题了。
Python random 库用的伪随机数生成算法是“Mersenne Twister”(MT)。这算法因其超长周期而被较多采纳。
然而,MT 这算法通不过一些随机数统计测验(TestU01 套件)。算法外部扩散性差,01 不平衡。对于须要独立随机数生成器的蒙特卡罗模仿来说,应用 MT 只在种子值(而不是其余参数)上有差别的多个实例通常并不适合。
我测试整顿出能通过多种随机数统计测验套件的 PRNG 算法,如下:
算法 | 周期 |
---|---|
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 |
而后实现了内含这些算法的伪随机数生成器 Py 库
源码放在 GitHub 上,
https://github.com/fsssosei/P…
曾经公布到了 PyPI 上,能够很不便的装置散发:
pip install pure-prng
导入
from pure_prng_package import pure_prng
很简略能够用起来,默认用的 PRNG 算法是 QCG
>>> seed = 170141183460469231731687303715884105727 #随便写的种子值
>>> prng_instance = pure_prng(seed)
>>> source_random_number = prng_instance.source_random_number()
>>> next(source_random_number)
65852230656997158461166665751696465914198450243194923777324019418213544382100
QCG、CCG 和 LCG64_32_ext 这三种是可变周期算法
>>> prng_instance = pure_prng(seed, new_prng_period = 2 ** 512)
>>> source_random_number = prng_instance.source_random_number()
>>> next(source_random_number)
8375486648769878807557228126183349922765245383564825377649864304632902242469125910865615742661048315918259479944116325466004411700005484642554244082978452
其余 PRNG 算法是固定周期算法
然而,库中有 method 可设置输入随机数序列的周期(不管哪种 PRNG 算法生成的随机数)
>>> period = 115792089237316195423570985008687907853269984665640564039457584007913129639747 #随便写的周期
>>> prng_instance = pure_prng(seed)
>>> rand_with_period = prng_instance.rand_with_period(period)
>>> next(rand_with_period)
mpz(65852230656997158461166665751696465914198450243194923777324019418213544381986)
库中还有 method 生成任意精度浮点随机数
>>> seed = 170141183460469231731687303715884105727
>>> prng_instance = pure_prng(seed)
>>> rand_float = prng_instance.rand_float(100)
>>> next(rand_float)
mpfr('0.56576176351048513846261940831522',100)