我正在运用随机库,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/
我很感激有关如何让程序在每次调用时生成新种子的建议:越简单越好。
我的平台:
答案 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_clock
(time()
通常具有一秒的分辨率,通常太低)例如:
#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);
}