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

标签 c++ c++11 random std mt19937

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

关于c++ - c++11 中只有 std::mt19937 的实例重复值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43900558/

相关文章:

c++ - 哪种未定义的行为允许这种优化?

c++ - OpenGL GLFW 窗口一打开就关闭

c++ - Gtest 新关键字

c++ - 如何在 C++ 中生成负随机整数

javascript - 如何为javascript中数组中的每个对象分配一个随机数?

c++ - 从 Visual Studio 2005 升级到 Visual Studio 2008 的陷阱

java - 给定的零索引数组 & 该数组的平衡索引

c++ - move 语义和 std::future

c++ - 如何在 C++ 中执行 Y = aX + Y

Python - 无重复数字的 5 位随机数生成器