【问题标题】:Linear congruential generator in C++C ++中的线性同余生成器
【发布时间】:2015-08-22 04:11:10
【问题描述】:

我写了一个简单的程序(实际上试图实现线性同余生成器),但我不太确定它是否能正常工作。

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

【问题讨论】:

  • 我建议保留A &lt; C 并在科学记数法中使用类似的指数。

标签: c++ random generator


【解决方案1】:

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

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

那么,prev 等于 C,这使得 prev A*C + C。但是,A*C 是如此之小,以至于当将其作为浮点数添加到前一个浮点数时,有效数字会被移出,而您只剩下之前的数字。

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

【讨论】:

  • 谢谢,一会儿再看,我的问题呢?是否可以选择代码将生成随机浮点数的 A 和 C?如果是这样,这些数字应该是多少?
  • @yak 从技术上讲(我不太擅长这个:)),A*C 的指数类似于C 本身的指数。与C 相比,我建议使A 更大更接近。整数给出更好的结果,因为添加一个整数与添加两个浮点数有很大不同 - 不会发生移位,也不会感觉到不精确。
  • 嗯,谢谢!将A 更改为0.9,将C 更改为0.01prev 更改为0.0001 实际上很有帮助:) 但是,以我的设置大小(我需要250 个随机数,天哪)我仍然有一些重复的数字.
  • @yak 你不必一个人做。首先,使用ints 生成数字可能会得到更好的结果,那么区间的划分就不是问题了。其次,你可以用一些已经在使用的数字来帮助自己:) en.wikipedia.org/wiki/…
【解决方案2】:

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

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

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

第三,根据您当前选择的参数,您不会遇到这种情况,但一般来说,您的中间计算应该使用long 来完成以避免溢出。 % 运算会将答案返回到 int,但如果您坚持使用 int 算法,则乘法可能不会产生确保完整周期长度和正确分布行为的数学正确值。

【讨论】:

  • prev = (A * prev + C) % (RAND_MAX + 1);(大约)因为 RAND_MAX 被定义为可能的结果之一。
猜你喜欢
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 2016-07-03
  • 2012-08-19
  • 2013-07-11
  • 1970-01-01
  • 2019-11-29
相关资源
最近更新 更多