正如标题所暗示的,我试图找到一种使用新的C++11
库生成随机数的方法。 我用以下代码尝试过:
std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);
我的代码的问题是,每次编译和运行它时,它总是生成相同的数字。 所以我的问题是,随机库中还有哪些功能可以在真正随机的同时完成这一点?
对于我的特定用例,我试图获取[1,10]
范围内的值
来自微软的Stephan T.Lavavej(stl)在Going Native上做了一次关于如何使用新的C++11随机函数以及为什么不使用rand()
的演讲。 在里面,他包括了一张幻灯片,基本上解决了你的问题。 我从下面的幻灯片中复制了代码。
你可以在这里看到他的演讲全文:http://channel9.msdn.com/events/goingnative/2013/rand-consexted-ballight
#include <random>
#include <iostream>
int main() {
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<double> dist(1.0, 10.0);
for (int i=0; i<16; ++i)
std::cout << dist(mt) << "\n";
}
我们使用random_device
一次来为名为mt
的随机数生成器植入种子。 random_device()
比MT19937
慢,但它不需要被植入种子,因为它从操作系统请求随机数据(这些数据将来自不同的位置,例如RDROND)。
查看此问题/答案,Uniform_Real_Distribution
似乎返回了一个[a,b)
范围内的数字,您需要[a,b]
的位置。为此,我们的Uniform_Real_Distribution
实际上应该如下所示:
std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));
我的“random”库提供了一个非常方便的C++11随机类的包装器。 你可以用一个简单的'get'方法做几乎所有的事情。
示例:
>
范围内的随机数
auto val = Random::get(-10, 10); // Integer
auto val = Random::get(10.f, -10.f); // Float point
随机布尔
auto val = Random::get<bool>( ) // 50% to generate true
auto val = Random::get<bool>( 0.7 ) // 70% to generate true
来自std::initilizer_list的随机值
auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
来自迭代器范围或所有容器的随机迭代器
auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
auto it = Random::get( vec ); // return random iterator
还有更多的事情! 查看github页面:
https://github.com/effolkronium/random
我把上面所有的东西都翻红了,还有大约40页用C++写的,然后看了Stephan T.Lavavej的视频“STL”,我仍然不知道随机数在实践中是如何工作的,所以我花了整整一个星期天来弄清楚它的全部内容,它的工作原理和使用方法。
在我看来,STL关于“不再使用srand”的说法是对的,他在视频2中解释得很好。 他还建议使用:
a)void random_device_uniform()
--用于加密生成,但速度较慢(来自我的示例)
b)MT19937
示例--速度更快,能够创建种子,不加密
我拿出了所有我能接触到的C++11书,找到了F.E。 像Breymann(2015)这样的德国作者仍然使用
srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or
只使用
而不是#includings-所以请注意只从一本书中学习:)。
意思-从C++11开始就不应该使用了,因为:
程序通常需要一个随机数源。 在新标准之前,C和C++都依赖于一个名为rand的简单C库函数。 该函数产生伪随机整数,这些伪随机整数均匀分布在从0到至少为32767的依赖于系统的最大值的范围内。 rand函数有几个问题:许多程序(如果不是大多数的话)需要的随机数范围与rand产生的范围不同。 有些应用程序需要随机浮点数。 有些程序需要反映非均匀分布的数字。 当程序员试图转换由RAND生成的数字的范围,类型或分布时,他们经常引入非随机性。 (引用自Lippmans C++入门版,2012年第五版)
我终于在Bjarne Stroustrups的20本书中找到了最好的解释--他应该知道他的东西--在《2019年C++之旅》,《2016年C++编程原则和实践》和《2014年C++编程语言第四版》中,还有《2012年Lippmans C++入门第五版》中的一些例子:
而且它真的很简单,因为随机数发生器由两部分组成:(1)产生随机或伪随机值序列的引擎。 (2)将这些值映射成一个范围内的数学分布的分布。
尽管Microsofts STL guy有这样的看法,Bjarne Stroustrups写道:
在中,标准库提供随机数引擎和分布(§24.7)。 默认情况下,使用default_random_engine,选择它是为了广泛的适用性和低成本。
void die_roll()
示例来自Bjarne Strousstrups--使用生成引擎和发行版的好主意(此处更详细)。
为了能够在
中实际使用标准库提供的随机数生成器,这里有一些带有不同示例的可执行代码,这些代码减少到最小的必要程度,希望能为你们节省时间和金钱:
#include <random> //random engine, random distribution
#include <iostream> //cout
#include <functional> //to use bind
using namespace std;
void space() //for visibility reasons if you execute the stuff
{
cout << "\n" << endl;
for (int i = 0; i < 20; ++i)
cout << "###";
cout << "\n" << endl;
}
void uniform_default()
{
// uniformly distributed from 0 to 6 inclusive
uniform_int_distribution<size_t> u (0, 6);
default_random_engine e; // generates unsigned random integers
for (size_t i = 0; i < 10; ++i)
// u uses e as a source of numbers
// each call returns a uniformly distributed value in the specified range
cout << u(e) << " ";
}
void random_device_uniform()
{
space();
cout << "random device & uniform_int_distribution" << endl;
random_device engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i=0; i<10; ++i)
cout << dist(engn) << ' ';
}
void die_roll()
{
space();
cout << "default_random_engine and Uniform_int_distribution" << endl;
using my_engine = default_random_engine;
using my_distribution = uniform_int_distribution<size_t>;
my_engine rd {};
my_distribution one_to_six {1, 6};
auto die = bind(one_to_six,rd); // the default engine for (int i = 0; i<10; ++i)
for (int i = 0; i <10; ++i)
cout << die() << ' ';
}
void uniform_default_int()
{
space();
cout << "uniform default int" << endl;
default_random_engine engn;
uniform_int_distribution<size_t> dist(1, 6);
for (int i = 0; i<10; ++i)
cout << dist(engn) << ' ';
}
void mersenne_twister_engine_seed()
{
space();
cout << "mersenne twister engine with seed 1234" << endl;
//mt19937 dist (1234); //for 32 bit systems
mt19937_64 dist (1234); //for 64 bit systems
for (int i = 0; i<10; ++i)
cout << dist() << ' ';
}
void random_seed_mt19937_2()
{
space();
cout << "mersenne twister split up in two with seed 1234" << endl;
mt19937 dist(1234);
mt19937 engn(dist);
for (int i = 0; i < 10; ++i)
cout << dist() << ' ';
cout << endl;
for (int j = 0; j < 10; ++j)
cout << engn() << ' ';
}
int main()
{
uniform_default();
random_device_uniform();
die_roll();
random_device_uniform();
mersenne_twister_engine_seed();
random_seed_mt19937_2();
return 0;
}
我认为这一切都加起来了,就像我说的,它花了我大量的阅读和时间来提炼它的例子-如果你有更多关于数字生成的东西,我很高兴听到通过pm或在评论部分,并将添加它,如果有必要或编辑这篇文章。 布尔