c++中的线性同余生成器

Linear congruential generator in C++

本文关键字:余生 线性 c++      更新时间:2023-10-16

我写了一个简单的程序(试图实现线性同余生成器实际上),但我不太确定它应该像它一样工作。

我想用我的生成器从[0,1]生成250个数字。然而,我得到的似乎不是随机数,而是相等的值。

如何改进它/我做错了什么?

代码如下:

#include <iostream>
#include <cmath>
static const double A = 0.001342;
static const double C = 0.00025194;
static const double RAND_MAX = 1.0;
double rand()
{
    static double prev = 0;
    prev = A * prev + fmod(C, RAND_MAX);
    return prev;
}
int main(int argc, char **argv)
{
    for(int i=0; i<6; i++)
    std::cout << rand() << "n";
    return 0;
}

输出:

0.00025194
0.000252278
0.000252279
0.000252279
0.000252279
0.000252279

切换到int而不是double,但是会得到一些不错的结果:

#include <iostream>
#include <cmath>
static const int A = 5;
static const int C = 3;
static const int RAND_MAX = 8;
double rand()
{
    static int prev = 1;
    prev = A * prev + (C % RAND_MAX);
    return prev;
}
int main(int argc, char **argv)
{
    for(int i=0; i<100; i++)
    std::cout << rand() << "n";
    return 0;
}
输出:

8
43
218
1093
5468
27343
136718
683593
3.41797e+06
1.70898e+07
8.54492e+07
4.27246e+08
2.13623e+09
2.09122e+09
1.86615e+09
7.40836e+08
-5.90786e+08
1.34104e+09
...

但是我需要它来生成大于等于0小于等于1的随机双位数:(

不是程序的问题,而是数字的选择。

prev一开始等于0,所以第一个数字变成C

prev = C,优先于A*C + C。然而,A*C太小了,当把它作为浮点数加到前一个浮点数上时,有效数字被移出,剩下的就是之前的数字。

你可以阅读更多关于浮点运算的知识

首先,不要对LCG使用浮点运算。浮点本质上是不精确的,并且可能导致不期望的行为,例如定点收敛或交错的短子周期。使用整数算法,数论可以告诉您哪些参数保证实现完整循环,即在0到M-1(其中M是您的模数)之间的每个值将获得。关于lcg的全周期参数要求和常用参数表,请参阅Wikipedia文章。

第二,你误解了LCG公式。应该是:

prev = (A * prev + C) % M;

第三,在你当前选择的参数下,你不会遇到这种情况,但通常你的中间计算应该用long来完成,以避免溢出。%运算将把答案带回int,但如果你坚持使用int运算,乘法可能不会产生数学上正确的值,从而保证完整的周期长度和正确的分布行为。