如何生成随机数种子?

3

我在查看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进行播种?


4
http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine/seed - πάντα ῥεῖ
大多数平台/系统都有一个具有密码学安全的伪随机数生成器(CSPRNG),尽管它们不是真正的随机数生成器,但它们基本上是不确定的。它们不需要由用户提供种子,并且根据系统的随机事件持续添加熵。 - zaph
2个回答

1

正如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};

我恢复了我的回答,这样你就可以看到我收到的评论。它被踩了,因为我不知道如何改进它。我使用<ctime>中的time,但除此之外,我没有看到与你的答案有太大的区别。 - 463035818_is_not_a_number
顺便提一下,我在Windows上使用原始代码时得到了重复序列。 - 463035818_is_not_a_number
不要使用当前时间作为随机种子。 - bowman han

0

例如,可以使用当前时间来初始化生成器:

#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;

1
当前时间是一个可怕的种子。时钟可能被操纵,多个进程在时钟分辨率内启动将获得相同的种子等等。作为 std::seed_seq 的输入的一部分,当前时间是可以接受的(如果与更多来源组合),然后该序列最终可以用于种子生成器。但是请不要直接使用原始时间来种植发生器。 - Jesper Juhl
@JesperJuhl 我应该怎么做才能修复它?添加一些偏移量吗? - 463035818_is_not_a_number
1
对于许多用途,使用原始时间作为种子是完全可以的。我们需要理解何时何地必须放弃简单的东西并开始使用复杂的东西。例如,如果您想执行蒙特卡罗积分,不需要结果可复制性,并且不要使用非常接近彼此启动的多个线程,则使用 time(0) 作为种子是完全可以接受的。 - quant_dev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接