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

时间:2013-10-29 18:01:08

标签: c++ c++11 random range

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

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

我的代码的问题是,每次编译和运行它时,它总是生成相同的数字。所以我的问题是随机库中的其他函数可以在真正随机的情况下实现这一点吗?

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

范围内的值

6 个答案:

答案 0 :(得分:168)

来自微软的Stephan T. Lavavej(stl)在Going Native上就如何使用新的C ++ 11随机函数以及为何不使用rand()进行了讨论。在其中,他包括一张幻灯片,基本上解决了你的问题。我已从下面的幻灯片中复制了代码。

你可以在这里看到他的全文:http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

#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慢,但不需要播种,因为它会从您的操作系统请求随机数据(例如,来自各个位置,例如RdRand)。< / p>


查看this question / answeruniform_real_distribution似乎返回[a, b)范围内您想要[a, b]的数字。为此,我们的uniform_real_distibution应该看起来像:

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

答案 1 :(得分:19)

我的&#39;随机&#39;库为C ++ 11随机类提供了一个高度方便的包装器。你可以通过一个简单的“get&#39;方法

示例:

  1. 范围内的随机数

    auto val = Random::get(-10, 10); // Integer
    auto val = Random::get(10.f, -10.f); // Float point
    
  2. 随机布尔

    auto val = Random::get<bool>( ) // 50% to generate true
    auto val = Random::get<bool>( 0.7 ) // 70% to generate true
    
  3. 来自std :: initilizer_list的随机值

    auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
    
  4. 来自迭代器范围或所有容器的随机迭代器

    auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
    auto it = Random::get( vec ); // return random iterator
    
  5. 还有更多的东西!查看github页面:

    https://github.com/effolkronium/random

答案 2 :(得分:2)

这是我刚才写的那些东西::

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

答案 3 :(得分:1)

我将上面的所有内容都涂成红色,其中约40个包含c ++的页面也this,并观看了video from Stephan T. Lavavej "STL" 仍然不确定随机数在实践中是如何工作的,所以我花了整整一个星期天来弄清楚它的全部含义,以及它如何工作和可以使用。

我认为STL关于“不再使用srand”是正确的,他在视频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> #includes-因此请注意仅从一本书中学习:)。

含义-自c ++ 11起不应该使用,因为:

  

程序通常需要一个随机数源。之前的新   标准,C和C ++都依赖于一个名为C的简单C库函数   兰德。该函数产生均匀一致的伪随机整数   分布范围从0到系统相关的最大值   至少是32767。   rand函数有几个问题:许多(如果不是大多数)程序   需要的随机数范围与由   兰德。某些应用程序需要随机浮点数。一些   程序需要能反映不均匀分布的数字。   程序员在尝试进行转换时通常会引入非随机性   rand生成的数字的范围,类型或分布。   (引用自Lippmans C ++入门2012年第五版)


我终于在Bjarne Stroustrups的新书中找到20本书中最好的解释-他应该知道他的东西-在“ C ++之旅2019”,“使用C ++ 2016编程原理和实践”和“ 《 C ++编程语言2014年第4版》以及“ Lippmans C ++入门第五版2012”中的一些示例:

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


尽管有微软STL专家的意见,但Bjarne Stroustrups写道:

  

在中,标准库提供随机数引擎和   发行版(§24.7)。默认情况下,使用default_random_engine,   选择它是为了具有广泛的适用性和低成本。

void die_roll()示例来自Bjarne Stroustrups-使用using (more bout that here)生成引擎和分发的好主意。


要能够实际使用标准库中提供的随机数生成器, <random> 此处将一些带有不同示例的可执行代码简化为希望达到的最低要求为您节省时间和金钱:

    #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或in评论部分,并将在必要时添加它或编辑此帖子。布尔

答案 4 :(得分:0)

这里有一些您可以阅读的有关伪随机数生成器的资源。

https://en.wikipedia.org/wiki/Pseudorandom_number_generator

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

替换

std::default_random_engine generator;

通过

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

答案 5 :(得分:-2)

您有两种常见情况。首先,您需要随机数字,并且对质量或执行速度不太感兴趣。在这种情况下,请使用以下宏

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

给你p在0到1的范围内 - epsilon(除非RAND_MAX大于double的精度,但是当你来到它时会担心)。

int x =(int)(uniform()* N);

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

如果您需要其他发行版,则必须转换p。或者有时几次调用uniform()会更容易。

如果你想要可重复的行为,请使用常量种子,否则使用time()调用种子。

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