使用 C + + 11随机库生成随机数

正如标题所示,我正在尝试找出一种使用新的 C + + 11 <random>库生成随机数的方法。我用这个代码试过了:

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

我的代码的问题是,每次我编译和运行它,它总是生成相同的数字。因此,我的问题是,随机库中还有哪些函数可以在真正随机的情况下实现这一点?

对于我的特定用例,我试图获得范围 [1, 10]内的值

197353 次浏览

微软的 Stephan T. Lavavej (stl)在“本地化”上做了一个关于如何使用新的 C + + 11随机函数以及为什么不使用 rand()的演讲。里面有一张幻灯片,基本上解决了你的问题。我从下面的幻灯片中复制了代码。

你可以看到他的完整谈话 给你:

#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一次种子随机数生成器命名为 mtrandom_device()mt19937慢,但是它不需要播种,因为它从您的操作系统请求随机数据(这些数据将来自不同的位置,例如 RdRand)。


查看 这个问题/答案,似乎 uniform_real_distribution返回一个范围为 [a, b)的数字,也就是您想要 [a, b]的位置。要做到这一点,我们的 uniform_real_distibution实际上应该看起来像:

std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));

你有两种常见的情况。首先,你需要随机的数字,不要太在意质量或执行速度。在这种情况下,使用以下宏

#define uniform() (rand()/(RAND_MAX + 1.0))

在0到1-ε 的范围内给出 p (除非 RAND _ MAX 的精度大于一个双精度,但是当你到达这个范围时要担心这个问题)。

Int x = (int)(统一() * N) ;

现在给出一个从0到 N -1的随机整数。

如果需要其他发行版,则必须转换 p,或者有时可以更容易地多次调用 unive()。

如果需要可重复的行为,则使用常量进行种子操作,否则使用 time ()调用进行种子操作。

现在,如果您对质量或运行时性能感到不安,请重写 univer()。除此之外,不要碰代码。始终保持均匀()在0到1减 ε。现在您可以包装 C + + 随机数库来创建一个更好的统一() ,但这是一种中级选项。如果您对 RNG 的特性感到困扰,那么花点时间了解底层方法是如何工作的也是值得的,然后提供一个。因此,您可以完全控制代码,并且可以保证使用相同的种子,序列将始终完全相同,无论您链接到的是哪个平台或哪个版本的 C + + 。

这是我刚才写的:

#include <random>
#include <chrono>
#include <thread>


using namespace std;


//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
public:
random_device                      rd;
mt19937                            mt;
uniform_real_distribution<double>  dist;


backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}


double rand() {
return dist(mt);
}
};


thread_local backoff_time_t backoff_time;




int main(int argc, char** argv) {
double x1 = backoff_time.rand();
double x2 = backoff_time.rand();
double x3 = backoff_time.rand();
double x4 = backoff_time.rand();
return 0;
}

~

我的“随机”库为 C + + 11随机类提供了一个非常方便的包装器。你可以用一个简单的“ get”方法做几乎所有的事情。

例子:

  1. 范围内的随机数

    auto val = Random::get(-10, 10); // Integer
    auto val = Random::get(10.f, -10.f); // Float point
    
  2. Random boolean

    auto val = Random::get<bool>( ) // 50% to generate true
    auto val = Random::get<bool>( 0.7 ) // 70% to generate true
    
  3. Random value from a std::initilizer_list

    auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
    
  4. Random iterator from iterator range or all container

    auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
    auto it = Random::get( vec ); // return random iterator
    

And even more things ! Check out the github page:

https://github.com/effolkronium/random

下面是一些关于伪随机数生成器的资源。

Https://en.wikipedia.org/wiki/pseudorandom_number_generator

基本上,计算机中的随机数需要一个种子(这个数字可以是当前系统时间)。

替换

std::default_random_engine generator;

作者

std::default_random_engine generator(<some seed number>);

我看了上面所有的东西,还有大约40页像 这个一样有 c + + 的内容,并且观看了来自 Stephan T. Lavavej“ STL”的视频 我仍然不确定随机数在实践中是如何工作的,所以我花了整整一个星期天去弄清楚它的全部内容,它是如何工作的,以及它是如何被使用的。

在我看来,STL 关于“不再使用沙子”的观点是正确的,他在视频 2中很好地解释了这一点。 他还建议使用:

A) void random_device_uniform()——用于加密生成,但速度较慢(参见我的示例)

B)使用 mt19937的例子——更快,能够创建种子,而不是加密


我找出了所有声称的 c + + 11书籍,我可以访问并发现像布雷曼(2015)这样的德国作家仍然使用克隆的

srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or

仅仅使用 <random>而不是 <time> and <cstdlib> # 包含-所以要小心只从一本书中学习:)。

意思是——从 c + + 11开始就不应该使用,因为:

程序通常需要一个随机数源 标准,C 和 C + + 都依赖于一个名为 这个函数产生伪随机整数 分布在从0到系统相关的最大值的范围内 至少是32767。 Rand 函数有几个问题: 即使不是大多数,也有许多程序 需要不同范围的随机数 有些应用程序需要随机浮点数。有些应用程序需要随机浮点数 程序需要反映非均匀分布的数字。 程序员在尝试转换时经常引入非随机性 由兰特产生的数字的范围、类型或分布。 (引自 Lippmans C + + Primer 2012第五版)


我最终在《2019年 C + + 之旅》、《2016年使用 C + + 的编程原理和实践》和《2014年 C++程式语言第四版》中找到了比亚内 · 斯特鲁斯特鲁普斯(bjarne stroustrups)的20本书中最好的解释——他应该知道他的东西——还有《2012年利普曼斯 c + + 初级读物第五版》中的一些例子:

这很简单,因为随机数生成器由两部分组成: (1)产生一系列随机或伪随机值的引擎。 (2)将这些值映射到一个范围内的数学分布的分布


尽管有微软 STL 的家伙的意见,Bjarne Stroustrup 写道:

其中,标准库提供了随机数引擎和 缺省情况下使用 default _ Random _ engine, 其选用适用范围广,成本低。

void die_roll()的例子是来自 Bjarne Stroustrups-好主意生成引擎和分发与 using (更多关于这里)


为了能够实际使用标准库中提供的随机数生成器,在这里,一些可执行代码与不同的例子减少到最不必要的,希望你们的安全时间和金钱:

    #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;
}

我认为这些都加起来了,就像我说的,我花了很多时间阅读这些例子-如果你有更多关于数字生成的东西,我很高兴通过下午或在评论部分听到这些,如果有必要的话,我会添加或编辑这篇文章。布尔