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

时间:2015-06-07 17:38:29

标签: c++ random generator

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

我想使用我的生成器从[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的随机双数:(

2 个答案:

答案 0 :(得分:3)

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

prev在开头等于零,因此第一个数字变为C

然后,prev等于C,这使得A*C + C。但是,A*C是如此之小,以至于将其作为浮点添加到前一个浮点时,有效数字会被移出,而您将保留之前所拥有的数字。

您可以在What Every Computer Scientist Should Know About Floating-Point Arithmetic上阅读更多内容。

答案 1 :(得分:2)

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

其次,你误解了LCG公式。它应该是:

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

第三,根据您当前选择的参数,您将不会遇到此问题,但通常您的中间计算应使用long来完成,以避免溢出。 %操作会将答案带回int,但如果您坚持使用int算术,则乘法可能不会产生数学上正确的值,从而确保完整的周期长度和正确的分布行为。