古老的LCG(linear congruential generator)代表了最好最朴素的伪随机数产生器算法。主要原因是容易理解,容易实现,而且速度快。

LCG 算法数学上基于公式:

X(n+1) = (a * X(n) + c) % m

其中,各系数为:

模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。

一般而言,高LCG的m是2的指数次幂(一般2^32或者2^64),因为这样取模操作截断最右的32或64位就可以了。多数编译器的库中使用了该理论实现其伪随机数发生器rand()。

下面是部分编译器使用的各个参数值:

Source m a c rand() / Random(L)的种子位 Numerical Recipes 2^32 1664525 1013904223 Borland C/C++ 2^32 22695477 1 位30..16 in rand(), 30..0 in lrand() glibc (used by GCC) 2^32 1103515245 12345 位30..0 ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++ 2^32 1103515245 12345 位30..16 Borland Delphi, Virtual Pascal 2^32 134775813 1 位63..32 of (seed * L) Microsoft Visual/Quick C/C++ 2^32 214013 2531011 位30..16 Apple CarbonLib 2^31-1 16807 0 见Park–Miller随机数发生器

LCG不能用于随机数要求高的场合,例如不能用于Monte Carlo模拟,不能用于加密应用。

LCG有一些严重的缺陷,例如如果LCG用做N维空间的点坐标,这些点最多位于m1/n超平面上(Marsaglia定理),这是由于产生的相继X(n)值的关联所致。

另外一个问题就是如果m设置为2的指数,产生的低位序列周期远远小于整体。
一般而言,输出序列的基数b中最低n位,bk = m (k是某个整数),最大周期bn.
有些场合LCG有很好的应用,例如内存很紧张的嵌入式中,电子游戏控制台用的小整数,使用高位可以胜任。

LCG的一种C++实现版本如下:

//************************************************************************ // Copyright (C) 2008 - 2009 Chipset // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //************************************************************************ #ifndef LCRANDOM_HPP_ #define LCRANDOM_HPP_ #include <ctime> class lcrandom { public: explicit lcrandom(size_t s = 0) : seed(s) { if (0 == seed) seed = std::time(0); randomize(); } void reset(size_t s) { seed = s; if (0 == seed) seed = std::time(0); randomize(); } size_t rand() { //returns a random integer in the range [0, -1UL) randomize(); return seed; } double real() { //returns a random real number in the range [0.0, 1.0) randomize(); return (double)(seed) / -1UL; } private: size_t seed; void randomize() { seed = 1103515245UL * seed + 12345UL; } }; class lcrand_help { static lcrandom r; public: lcrand_help() {} void operator()(size_t s) { r.reset(s); } size_t operator()() const { return r.rand(); } double operator()(double) { return r.real(); } }; lcrandom lcrand_help:: r; extern void lcsrand(size_t s) { lcrand_help()(s); } extern size_t lcirand() { return lcrand_help()(); } extern double lcdrand() { return lcrand_help()(1.0); } #endif // LCRANDOM_HPP_

如果需要高质量的伪随机数,内存充足(约2kb),Mersenne twister算法是个不错的选择。Mersenne twister产生随机数的质量几乎超过任何LCG。不过一般Mersenne twister的实现使用LCG产生种子。

Mersenne twister是Makoto Matsumoto (松本)和Takuji Nishimura (西村)于1997年开发的伪随机数产生器,基于有限二进制字段上的矩阵线性再生。可以快速产生高质量的伪随机数,修正了古老随机数产生算法的很多缺陷。 Mersenne twister这个名字来自周期长度通常取Mersenne质数这样一个事实。常见的有两个变种Mersenne Twister MT19937和Mersenne Twister MT19937-64。

Mersenne Twister有很多长处,例如:周期2^19937 - 1对于一般的应用来说,足够大了,序列关联比较小,能通过很多随机性测试。
关于Mersenne Twister比较详细的论述请参阅http://www.cppblog.com/Chipset/archive/2009/01/19/72330.html

用Mersenne twister算法实现的伪随机数版本非常多。例如boost库中的高质量快速随机数产生器就是用Mersenne twister算法原理编写的。

下面是Mersenne twister的一个C++实现:

//************************************************************************ // This is a slightly modified version of Equamen mersenne twister. // // Copyright (C) 2009 Chipset // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //************************************************************************ #ifndef mtrandom_HPP_ #define mtrandom_HPP_ #include <stddef.h> class mtrandom { public: mtrandom() : left(1) { init(); } explicit mtrandom(size_t seed) : left(1) { init(seed); } mtrandom(size_t* init_key, int key_length) : left(1) { int i = 1, j = 0; int k = N > key_length ? N : key_length; init(); for(; k; --k) { state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL))+ init_key[j] + j; // non linear state[i] &= 4294967295UL; // for WORDSIZE > 32 machines ++i; ++j; if(i >= N) { state[0] = state[N - 1]; i = 1; } if(j >= key_length) j = 0; } for(k = N - 1; k; --k) { state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i; // non linear state[i] &= 4294967295UL; // for WORDSIZE > 32 machines ++i; if(i >= N) { state[0] = state[N - 1]; i = 1; } } state[0] = 2147483648UL; // MSB is 1; assuring non-zero initial array } void reset(size_t rs) { init(rs); next_state(); } size_t rand() { size_t y; if(0 == --left) next_state(); y = *next++; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } double real() { return (double)rand() / -1UL; } // generates a random number on [0,1) with 53-bit resolution double res53() { size_t a = rand() >> 5, b = rand() >> 6; return (a * 67108864.0 + b) / 9007199254740992.0; } private: void init(size_t seed = 19650218UL) { state[0] = seed & 4294967295UL; for(int j = 1; j < N; ++j) { state[j] = (1812433253UL * (state[j - 1] ^ (state[j - 1] >> 30)) + j); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array state[]. // 2002/01/09 modified by Makoto Matsumoto state[j] &= 4294967295UL; // for >32 bit machines } } void next_state() { size_t* p = state; int i; for(i = N - M + 1; --i; ++p) *p = (p[M] ^ twist(p[0], p[1])); for(i = M; --i; ++p) *p = (p[M - N] ^ twist(p[0], p[1])); *p = p[M - N] ^ twist(p[0], state[0]); left = N; next = state; } size_t mixbits(size_t u, size_t v) const { return (u & 2147483648UL) | (v & 2147483647UL); } size_t twist(size_t u, size_t v) const { return ((mixbits(u, v) >> 1) ^ (v & 1UL ? 2567483615UL : 0UL)); } static const int N = 624, M = 397; size_t state[N]; size_t left; size_t* next; }; class mtrand_help { static mtrandom r; public: mtrand_help() {} void operator()(size_t s) { r.reset(s); } size_t operator()() const { return r.rand(); } double operator()(double) { return r.real(); } }; mtrandom mtrand_help:: r; extern void mtsrand(size_t s) { mtrand_help()(s); } extern size_t mtirand() { return mtrand_help()(); } extern double mtdrand() { return mtrand_help()(1.0); } #endif // mtrandom_HPP_

(注:部分内容摘自:《产生伪随机数两种常用算法》http://bbs.pfan.cn/post-293562.html)

RNG分析:线性同余法 LCG相关推荐

  1. 【随机数生成算法系列】线性同余法和梅森旋转法

    一般我们用到的随机算法都是伪随机算法,什么叫伪随机算法呢?伪随机算法意思是假如知道第一个随机种子和随机算法的话就可以推算出下一个随机数.通常我们程序里都是通过当前时间作为随机函数的第一个随机种子,然后 ...

  2. java实现基金浮动_Java: 实现自回归分析/线性回归分析/基金各项指标计算等

    版权声明:本文为博主原创文章,未经博主允许不得转载. 需Jama矩阵运算库. java版源码: 包含自回归分析/线性回归分析/基金各项指标计算 import Jama.Matrix; public c ...

  3. 随机算法求pi、线性同余法求random、拉斯维加斯算法python

    一.随机算法求pi # 计算圆周率 import pdb import random def CalcPai(n):# 计算π值k = 0for i in range(0,n):x = random. ...

  4. 深度学习原理—代码分析线性分类与神经网络分类的区别

    https://www.toutiao.com/a6687727778487337476/ 利用sklearn.dataset随机产生数据,随机生成两类数据,用不同的颜色展示出来,如下图: 产生的随机 ...

  5. 线性同余法产生随机数C语言,线性同余生成随机数的一点思考

    今天下午 pk 和我讨论了一个问题,他看到在另一个项目组的 lua 代码里有一段使用线性同余产生随机数的代码,但是那个项目组的同事告诉他这个函数生成的随机数是分布不均的.于是他想到了我前两天给他讲的关 ...

  6. HDU-1014 线性同余法

    Problem Description Computer simulations often require random numbers. One way to generate pseudo-ra ...

  7. 计算机LCG/PCG/MWC/XorShift等PRNG算法,以及V8中Math.random()、webkit中crypto等随机算法的实现

    计算机LCG/PCG/MWC/XorShift等PRNG算法,以及V8中Math.random().webkit中crypto等随机算法的实现 本文篇幅较长,如想直接看 js 的随机数实现可定位本文E ...

  8. 生成随机数c 语言,C 语言随机数生成器的实现分析

    (点击上方公众号,可快速关注) 如需转载,发送「转载」二字查看说明 本文是为了记录和澄清一个由来已久的关于C语言随机数生成器的误解. 目前所看到的所有公开的关于C随机数生成器的中文资料,都提到经典的线 ...

  9. 在VC++中生成伪随机数祥解

    摘 要 伪随机数在计算机软件设计中有很广泛的用途.本文介绍了基于数学方法的利用计算机产生伪随机数的一种方法,即线性同余法,任何伪随机数的产生都是运用递推的原理来生成的.以及在Visual C++环境中 ...

最新文章

  1. linux下kerberos教程
  2. oracle数据误操作恢复【flashback闪回操作】
  3. python爬虫网络请求超时是什么意思_爬虫请求超时设置
  4. django 1.8 官方文档翻译: 3-4-2 内建显示视图
  5. class-dump获取iOS私有api
  6. [Leedcode][JAVA][第560题][和为K的子数组][Hashmap][数组]
  7. HC-05蓝牙模块AT指令调试
  8. mfc chartctrl 饼状图编写_鸡蛋饼
  9. CI加载model的问题
  10. 截取年月日在hana中怎么写_SAP HANA跟我学HANA系列之日期函数总结
  11. Axure RP 8.0 Mac中文破解版链接
  12. 关掉计算机usb接口,bios中不小心把电脑的USB接口给关闭了,怎么样开启
  13. php获取ip归属地
  14. 寄存柜程序模拟(C语言)
  15. 跳过Nexus7第一次开机设置的网络验证
  16. epoch如何设置_最易懂的方式介绍 神经网络模型中的Epoch、Iteration、Batchsize
  17. 异或为什么满足结合律,布尔代数与布尔环简介
  18. Oracle 考试概要
  19. 适用于 Windows 10/11 电脑 的 5 大好用的离线录屏软件
  20. MAVEN Plugins 插件官网下载

热门文章

  1. php用户注册自动生成邀请码,PHP如何实现根据用户id生成一个唯一邀请码
  2. 解决WIN8小凡不能应用的办法!
  3. 小灵通听证?这些律师是不识字还是不懂法?
  4. 工作中MNU010 至 MNU140表的名称及作用
  5. 汕头大学信息与计算机学院研究生院,汕头大学研究生院
  6. Java Service Wrapper 使用经验总结
  7. xilinx官网申请IP
  8. 服务器操作系统怎么做映像,如何网络捕获使用 Sysprep 和 PXE 配置的服务器操作系统映像...
  9. 手机文档怎样通过计算机打印,惠普M1218怎么使用手机打印文件?电脑与电脑之间怎么共享打印机打印?...
  10. 吴恩达老师DeepLearning系列课程最详细学习笔记之23—Jupyter Ipython笔记本的快速指南