【问题标题】:How to seed random number generator? [duplicate]如何播种随机数生成器? [复制]
【发布时间】:2016-08-08 08:44:06
【问题描述】:

我正在查看cppreference.com 生成正态分布随机数的示例,并稍微重构了代码以得到这个:

#include <iostream>
#include <random>

struct MyNormalDistribution {
    static double getRandomNumber(double mean,double std_dev){
        return std::normal_distribution<>(mean,std_dev)(MyNormalDistribution::generator);
    }
    private:
        static std::random_device rand;
        static std::mt19937 generator;
};
std::random_device MyNormalDistribution::rand;
std::mt19937 MyNormalDistribution::generator = std::mt19937(MyNormalDistribution::rand());

int main(int argc, char *argv[]) {
    for (int t=0;t<10;t++){
        std::cout << MyNormalDistribution::getRandomNumber(0,10) << std::endl;
    }
}

但是,每当我运行它时,我都会得到相同的数字序列。是否有一些愚蠢的错误,或者 cppreference 上的示例没有包括正确的播种?

如何正确播种MyNormalDistribution

【问题讨论】:

  • 大多数平台/系统都有一个加密安全的伪随机数生成器 (CSPRNG),虽然不是真正的 RNG,但它们本质上是非确定性的。它们不需要由用户播种,并且会根据系统随机出现持续添加熵。

标签: c++ c++11 random random-seed


【解决方案1】:

例如,可以使用当前时间为生成器播种:

#include <iostream>
#include <random>

struct MyGenerator {
    std::mt19937 gen;
    static std::random_device rand;
    MyGenerator() : generator(rand()){ gen.seed(time(0)); }
};
std::random_device MyGenerator::rand;
struct MyNormalDistribution {
    static double getRandomNumber(double mean,double std_dev){
        return std::normal_distribution<>(mean,std_dev)(MyNormalDistribution::gen.gen);
    }
    private:
        static MyGenerator gen;
};
MyGenerator MyNormalDistribution::gen;

【讨论】:

  • 当前时间是一颗可怕的种子。时钟可以被操纵,在时钟分辨率内开始的多个处理将获得相同的种子等。作为std::seed_seq 输入的一部分,当前时间是可以的(如果结合更多源),然后该序列最终可以用于种子生成器。但请不要使用原始时间直接为生成器播种 - 请。
  • @JesperJuhl 我应该怎么做才能解决它?添加一些偏移量?
  • 对于许多使用原始时间作为种子的用途来说是完全可以的。人们需要了解何时何地我们必须放弃简单的事物并开始使用复杂的事物。例如。如果你想进行蒙特卡洛积分,不要求结果的可复制性,并且不使用时间上彼此非常接近的多个线程,那么使用time(0)作为种子是完全可以接受的。
【解决方案2】:

正如cppreference.com 所写,“问题”在您的 std::random_device 中:

std::random_device 可以根据 实现定义的伪随机数引擎,如果 非确定性源(例如硬件设备)不可用于 实施。在这种情况下,每个 std::random_device 对象可能 生成相同的数列。

换句话说,我认为您使用的是 Linux 操作系统,并且您的内核中没有设置“CONFIG_HW_RANDOM”选项。作为替代方案,您可以只使用其他种子值来源,例如系统时钟。

auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 generator {seed};

【讨论】:

  • 我取消了我的答案,所以你可以阅读我收到的评论。它被否决了,我删除了它,因为我不知道如何改进它。我使用来自&lt;ctime&gt;time,但除此之外我看不出你的答案有什么大的不同。
  • 顺便说一句,我在 Windows 上使用原始代码得到了重复序列。
  • 不使用当前时间作为随机种子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 2015-03-14
  • 2012-09-01
  • 1970-01-01
  • 2019-07-16
  • 2016-07-22
  • 1970-01-01
相关资源
最近更新 更多