最近,我正在尝试使用random engines
中定义的#include<random>
在C ++中生成随机数的程序。我的计划如下: -
#include <iostream>
#include <random>
#include <chrono>
using namespace std;
int random (int lim)
{
default_random_engine dre (chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<> uid(1,lim);
return uid(dre);
}
int main()
{
for (int i=0;i<10;++i)
cout<<random(100)<<" ";
return 0;
}
简单,绝对!但是当我尝试输出时,这些数字不那么随机: -
66 95 95 96 96 96 96 96 97 97
当我略微改变我的程序时将default_random_engine
声明为static
或将其设为global
然后我的输出正确如下: -
62 53 21 38 7 51 46 40 86 12
有人能指出我的程序最初和实际出现的问题吗?小变化是如何帮助我获得更好的输出的呢?
答案 0 :(得分:6)
每次运行random
时,您都会使用相同或非常接近相同种子的方式重新生成生成器,以便每次迭代都获得相同的输出,或者如果它确实发生更改,则不会太多。
要解决此问题,您只需为生成器播种一次,然后继续调用它。通过将其设置为静态,它可以正常工作,因为生成器仅在您继续其随机序列时创建并播种,而不是获取它将创建的第一个随机数。
通常,随机数生成器具有通过算法放置的内部值,算法吐出的内容是它们为随机数返回的内容。然后保留该数字用于算法的下一次迭代。这就是我们获得随机序列的方式。
如果我们使用相同的种子,我们将获得与从相同数字开始的相同输出序列。在您的情况下,您的种子只会在每次chrono::steady_clock::now()
前进时更改,并且您的循环运行速度要快于每次调用的时间(种子)。
答案 1 :(得分:1)
关于伪随机数生成器的一个重要事项是它们产生一系列数字,而“随机性”是测试序列的质量。也就是说,您不能说特定数字是随机的(is '4' a random number?)。而是说出数字序列是否是随机的。
当您“播种”pRNG时,您通常会选择它可以生成的序列之一,并且这些数字相对于序列的其余部分是随机的。因此,一般情况下,如果您想要“随机性”,您首先要选择一个特定的序列,然后使用该特定随机序列中的连续数字。
在没有static
的代码中,您在循环的每次迭代中选择一个序列,然后使用该序列中的一个数字。由于您没有使用来自相同序列的许多值,因此结果看起来并不是随机的并不奇怪。
当您添加static
时,引擎不再在循环的每次迭代中播种。相反,它被播种一次,循环的每次迭代都使用来自该序列的连续值,就像你应该做的那样。这就是static
对块作用域变量的意义:它意味着变量存在于它声明的块的外部,并且它只会在第一次初始化。
static
可以解决您的问题,但我认为这不是一个好的解决方案。 static
变量与全局变量有一些相似之处,并导致一些相同的问题。相反,我建议你明确地将引擎移出循环。例如:
int random (int lim, default_random_engine &dre)
{
uniform_int_distribution<> uid(1,lim);
return uid(dre);
}
int main()
{
default_random_engine dre (chrono::steady_clock::now().time_since_epoch().count());
for (int i = 0; i < 10; ++i)
{
cout << random(100, dre) << " ";
}
}
现在正在显式管理状态并将其传递到random()
函数,这比依赖于块作用域static
变量的隐藏和隐式行为更好。
一般而言,我不建议将时间用作种子数据的唯一来源。低分辨率时钟可能不会足够频繁地提供新种子,并且同时在不同位置运行的程序可以使用相同的种子。
我对播种的建议是:
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
(初学者无需知道mt19937或其他任何内容是什么。他们只需知道将其粘贴到适当的位置以及如何使用eng
。在您的代码中,您需要需要将default_random_engine
的每次使用替换为mt19937
。)