В программе часто в разных классах генерируются случайные числа. Поэтому я хочу создать класс, который возвращает один экземпляр генератора std :: mt19937. Я также принимаю во внимание, что некоторые компиляторы не работают с std :: random_device (Для этого проверьте значение энтропии). Я создал класс синглтон.
#include <iostream>
#include <random>
#include <chrono>
class RandomGenerator
{
public:
static RandomGenerator& Instance() {
static RandomGenerator s;
return s;
}
std::mt19937 get();
private:
RandomGenerator();
~RandomGenerator() {}
RandomGenerator(RandomGenerator const&) = delete;
RandomGenerator& operator= (RandomGenerator const&) = delete;
std::mt19937 mt;
};
RandomGenerator::RandomGenerator() {
std::random_device rd;
if (rd.entropy() != 0) {
mt.seed(rd());
}
else {
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
mt.seed(seed);
}
}
std::mt19937 RandomGenerator::get() {
return mt;
}
int main() {
std::mt19937 &mt = RandomGenerator::Instance().get();
std::uniform_real_distribution<double> dist(0.0, 1.0);
for (std::size_t i = 0; i < 5; i++)
std::cout << dist(mt) << "\n";
std::cout << "\n";
std::mt19937 &mt2 = RandomGenerator::Instance().get();
std::uniform_real_distribution<double> dist2(0.0, 1.0);
for (std::size_t i = 0; i < 5; i++)
std::cout << dist2(mt2) << "\n";
return 0;
}
Но когда я выхожу из класса генератора std :: mt19937, случайные числа начинают повторяться. Как этого избежать?
0.389459
0.68052
0.508421
0.0758856
0.0137491
0.389459
0.68052
0.508421
0.0758856
0.0137491
Постскриптум Есть ли лучший способ инициализировать генератор, чем время?
Решение
Протестировано это под следующими компиляторами: Visual Studio, MinGW, DevC ++.
#include <iostream>
#include <random>
#include <chrono>
class RandomGenerator
{
public:
static RandomGenerator& Instance() {
static RandomGenerator s;
return s;
}
std::mt19937 & get();
private:
RandomGenerator();
~RandomGenerator() {}
RandomGenerator(RandomGenerator const&) = delete;
RandomGenerator& operator= (RandomGenerator const&) = delete;
std::mt19937 mt;
};
RandomGenerator::RandomGenerator() {
std::random_device rd;
if (rd.entropy() != 0) {
mt.seed(rd());
}
else {
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
mt.seed(seed);
}
}
std::mt19937 & RandomGenerator::get() {
return mt;
}
int main() {
std::mt19937 &mt = RandomGenerator::Instance().get();
std::uniform_real_distribution<double> dist(0.0, 1.0);
for (std::size_t i = 0; i < 5; i++)
std::cout << dist(mt) << "\n";
std::cout << "\n";
std::mt19937 &mt2 = RandomGenerator::Instance().get();
std::uniform_real_distribution<double> dist2(0.0, 1.0);
for (std::size_t i = 0; i < 5; i++)
std::cout << dist2(mt2) << "\n";
return 0;
}
std::mt19937 get();
возвращает копию. Каждый раз, когда вы звоните get()
Вы делаете копию исходного состояния двигателя. mt19937
является псевдослучайным механизмом, каждое состояние создает предопределенную последовательность. Если состояния двух экземпляров идентичны, они произведут одинаковую последовательность. Сделайте так, чтобы функция возвращала ссылку, чтобы состояние единственного экземпляра обновлялось с каждым новым сгенерированным числом.
std::mt19937 & RandomGenerator::get() {
return mt;
}
Других решений пока нет …