我对编程很陌生。我有一个关于使用c++11随机头来生成随机数的问题。我试着学习,但没有成功。最近,我尝试了以下方法,并且成功了。关于如何改进它的任何建议。有一个好的来源来了解更多这方面的知识吗?
下面是代码:
#include <iostream>
#include <random>
#include <ctime>
int main()
{
std::default_random_engine random_engine(time(0));
for (int i = 1; i <= 100; i++)
{
std::uniform_int_distribution<int> num(1, 100);
std::cout << i << "==> " << num(random_engine) << std::endl;
}
return 0;
}
发布于 2020-12-25 01:37:13
首先,请注意,std::default_random_engine
和std::uniform_int_distribution<int>
在同一意义上都是不可移植的,就像rand()
不可移植一样:它们不会在不同的平台上产生相同的数字序列,因为它们的行为是由实现定义的。对于uniform_int_distribution
来说,实际上没有可移植的替代方案,所以它是镇上最好的游戏。但是对于PRNG本身,我不认为任何专家会推荐default_random_engine
。只需选择一个已知的引擎,如std::mt19937
。(这是不太好,但这也是目前镇上唯一的游戏。)
对于种子:请注意,您只向PRNG的构造函数提供了32位种子(以及一个非常可预测的种子)。您应该从random_device
中播种,类似于这样(从这里偷来的):
std::random_device rd;
int data[624];
std::generate_n(data, std::size(data), std::ref(rd));
std::seed_seq sseq(data, std::end(data));
std::mt19937 g(sseq);
(当然,在实践中没有人这样做。)
for (int i = 1; i <= 100; i++)
首选
for (int i = 0; i < 100; ++i)
即使这意味着您必须在循环中引用i+1
。在C和C++以及每种现代语言中,使用从0开始的半开放范围是很好的实践。
std::uniform_int_distribution<int> num(1, 100);
就我个人而言,我会写成
auto dist = std::uniform_int_distribution<int>(1, 100);
以获得一个漂亮的清晰=
分离可见一目了然。另外,请注意我的常规变量名:rd
用于随机设备,g
用于PRNG本身,dist
用于分发。使用比dist
更具有描述性的名称可能是有意义的.但是毫无疑问,num
并不是描述性更强,而num
则不那么真实--发行版不是单个数字!
最后,您不需要最终的return 0
(默认情况下,main
返回0),也不需要std::endl
,因为'\n'
(或"\n"
)也一样。
但是基本上你做的是正确的:在循环之外创建的PRNG,从循环内部调用类似a函数的发行版。
如果需要,也可以将发行版的变量定义移出循环之外。在实践中,这可能并不重要,因为uniform_int_distribution
不太可能在迭代之间保留任何状态。但是,如果它是一个std::normal_distribution
,那么每次通过循环销毁和重新创建分发将基本上要花费您速度的50%。
auto dist = std::uniform_int_distribution<int>(1, 100);
for (int i = 0; i < 100; ++i) {
std::cout << (i+1) << "==> " << dist(g) << '\n';
}
发布于 2020-12-25 01:56:04
不幸的是,我不知道有什么源代码能够很好地介绍标准<random>
库。我几年前就写过这篇文章,但那时它还是全新的,我主要是在介绍它;它并不是一个真正全面的教程。
不过,我可以给您一些关于代码的建议。
std::default_random_engine random_engine(time(0));
使用std::time()
为随机数生成器添加种子通常是不明智的,原因有很多。
首先,不能保证返回类型实际上可以用作种子,因为它可能不能转换为无符号整数类型。(实际上,我从未见过这样的平台,因为返回类型是所有POSIX平台上32位签名的int
)。
其次,返回类型通常(可能总是)只有1秒左右。这意味着,如果程序在一秒钟内运行两次,它将产生完全相同的“随机”序列。
第三,这是一个可预测的价值。如果我想控制你的程序,我所要做的就是把我的时钟设置为一个时间来生成我想要的序列。
在实践中,随机引擎种子的通常方法是使用std::random_device
。现在它通常是不确定的(所以,完全不可预测),但它是那些不能保证在任何地方都能正常工作的东西之一(尽管它几乎肯定在大多数人需要的地方都能正常工作)。
所以你要做的就是:
std::random_device rd;
std::default_random_engine random_engine(rd());
// or, in one line:
std::default_random_engine random_engine(std::random_device{}());
下一步:
for (int i = 1; i <= 100; i++)
{
std::uniform_int_distribution<int> num(1, 100);
std::cout << i << "==> " << num(random_engine) << std::endl;
}
将分发移出循环可能更有效:
std::uniform_int_distribution<int> dist(1, 100);
for (int i = 1; i <= 100; i++)
{
std::cout << i << "==> " << dist(random_engine) << '\n';
}
最后,给出一些简单的建议:
mersenne_twister_engine
和linear_congruential_engine
。mt19937
(即mersenne_twister_engine
)应该是您的默认选择。我在模拟中使用了LCG,其中每个实体都有自己的随机数生成器,因为Mersenne是伟大的…但也是巨大的和相对缓慢的。LCG很小,而且速度很快,但不会产生很大的随机性…但有时候这没什么。uniform_int_distribution
和normal_distribution
。bernoulli_distribution
,来模拟一些事情,比如说,62%的成功机会被一遍又一遍地完成。但即便如此,我通常也只是使用正态分布。param()
函数。https://codereview.stackexchange.com/questions/253883
复制相似问题