C ++ 11:如何使用<random>

时间:2015-12-28 09:09:06

标签: c++11 random

我正在运用随机库,C ++ 11的新手。我写了以下最小程序:

#include <iostream>
#include <random>
using namespace std;
int main() {
    default_random_engine eng;
    uniform_real_distribution<double> urd(0, 1);
    cout << "Uniform [0, 1): " << urd(eng);
}

当我反复运行它时,它每次都会给出相同的输出:

>a
Uniform [0, 1): 0.131538
>a
Uniform [0, 1): 0.131538
>a
Uniform [0, 1): 0.131538

我希望程序在每次调用时都设置不同的种子,这样每次都会生成一个不同的随机数。我知道随机提供了一个名为seed_seq的工具,但我发现它的解释(在cplusplus.com上)完全模糊不清:

http://www.cplusplus.com/reference/random/seed_seq/

我很感激有关如何让程序在每次调用时生成新种子的建议:越简单越好。

我的平台:

2 个答案:

答案 0 :(得分:10)

拥有seed_seq的目的是增加生成序列的熵。如果您的系统上有random_device,则可以使用该随机设备中的多个数字进行初始化。在具有伪随机数生成器的系统上,我不认为随机性有所增加,即生成序列熵。

立足于你的方法:

如果您的系统确实提供了随机设备,那么您可以像这样使用它:

  std::random_device r;
  // std::seed_seq ssq{r()};
  // and then passing it to the engine does the same
  default_random_engine eng{r()};
  uniform_real_distribution<double> urd(0, 1);
  cout << "Uniform [0, 1): " << urd(eng);

如果您的系统没有随机设备,那么您可以使用time(0)作为random_engine的种子

  default_random_engine eng{static_cast<long unsigned int>(time(0))};
  uniform_real_distribution<double> urd(0, 1);
  cout << "Uniform [0, 1): " << urd(eng);

如果您有多个随机源,您实际上可以执行此操作(例如2)

std::seed_seq seed{ r1(), r2() };
  default_random_engine eng{seed};
  uniform_real_distribution<double> urd(0, 1);
  cout << "Uniform [0, 1): " << urd(eng);

其中r1,r2是不同的随机设备,例如热噪声量子源

当然你可以混合搭配

std::seed_seq seed{ r1(), static_cast<long unsigned int>(time(0)) };
  default_random_engine eng{seed};
  uniform_real_distribution<double> urd(0, 1);
  cout << "Uniform [0, 1): " << urd(eng);

最后,我想用一个班轮进行初始化:

  auto rand = std::bind(std::uniform_real_distribution<double>{0,1},
              std::default_random_engine{std::random_device()()});
  std::cout << "Uniform [0,1): " << rand();

如果您担心time(0)具有第二精度,您可以通过high_resolution_clock请求bames23 below首先指定的纪元以来的时间来解决此问题:

static_cast<long unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()) 

或者只是玩CPU随机性

long unsigned int getseed(int const K)
{

    typedef std::chrono::high_resolution_clock hiclock;

    auto gett= [](std::chrono::time_point<hiclock> t0)
    {
        auto tn = hiclock::now();
        return static_cast<long unsigned int>(std::chrono::duration_cast<std::chrono::microseconds>(tn-t0).count());
    };

    long unsigned int diffs[10];
    diffs[0] = gett(hiclock::now());
    for(int i=1; i!=10; i++)
    {
        auto last = hiclock::now();
        for(int k=K; k!=0; k--)
        {
            diffs[i]= gett(last);
        }
    }

    return *std::max_element(&diffs[1],&diffs[9]);
}

答案 1 :(得分:6)

#include <iostream>
#include <random>

using namespace std;

int main() {
    std::random_device r;                                       // 1
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; // 2
    std::mt19937 eng(seed);                                     // 3

    uniform_real_distribution<double> urd(0, 1);

    cout << "Uniform [0, 1): " << urd(eng);
}

为了从伪随机数生成器获得不可预测的结果 我们需要一个不可预测的种子数据来源。在 1 上我们创建一个 为此目的std::random_device。上 2 我们使用std::seed_seq进行组合 由random_device产生的几个值,形成适合播种的形式 伪随机数发生器。输入的数据越不可预测 seed_seq,种子引擎的结果越不可预测 是。在 3 上,我们使用seed_seq创建一个随机数引擎来播种 引擎的初始状态。

seed_seq可用于初始化多个随机数引擎; seed_seq每次使用时都会生成相同的种子数据。

注意:并非所有实施都提供非确定性数据的来源。 查看std::random_device的实施文档。

如果您的平台未提供非确定性random_device,则可以使用其他一些来源进行播种。文章Simple Portable C++ Seed Entropy提出了许多其他来源:

  • 高分辨率时钟,例如std::chrono::high_resolution_clocktime()通常具有一秒的分辨率,通常太低)
  • 现代操作系统因地址空间布局随机化(ASLR)而异的内存配置
  • CPU计数器或随机数生成器。 C ++不提供对这些的标准化访问,因此我不会使用它们。
  • 线程ID
  • 一个简单的计数器(只有在你不止一次种子时才重要)

例如:

#include <chrono>
#include <iostream>
#include <random>
#include <thread>
#include <utility>

using namespace std;

// we only use the address of this function
static void seed_function() {}

int main() {
    // Variables used in seeding
    static long long seed_counter = 0;
    int var;
    void *x = std::malloc(sizeof(int));
    free(x);

    std::seed_seq seed{
        // Time
        static_cast<long long>(std::chrono::high_resolution_clock::now()
                                   .time_since_epoch()
                                   .count()),
        // ASLR
        static_cast<long long>(reinterpret_cast<intptr_t>(&seed_counter)),
        static_cast<long long>(reinterpret_cast<intptr_t>(&var)),
        static_cast<long long>(reinterpret_cast<intptr_t>(x)),
        static_cast<long long>(reinterpret_cast<intptr_t>(&seed_function)),
        static_cast<long long>(reinterpret_cast<intptr_t>(&_Exit)),
        // Thread id
        static_cast<long long>(
            std::hash<std::thread::id>()(std::this_thread::get_id())),
        // counter
        ++seed_counter};

    std::mt19937 eng(seed);

    uniform_real_distribution<double> urd(0, 1);

    cout << "Uniform [0, 1): " << urd(eng);
}