只有 std::mt19937 的实例在 c++11 中重复值

Only instance of std::mt19937 repeats values in c++11

本文关键字:c++11 实例 std mt19937 只有      更新时间:2023-10-16

在程序中,通常在不同的类中生成随机数。所以我想创建一个返回生成器 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;
}