C++ 如何引用随机发生器?

C++ 如何引用随机发生器?,c++,c++11,visual-c++,C++,C++11,Visual C++,我试图在一定范围内生成随机数。我有多个线程中的多个对象将调用这个函数,这个函数在一个单例类中,因此只有一个对象被调用。但我注意到,我的随机数更接近范围的中间值,因此,在前200次通话中,它们彼此接近,然后开始在给定范围内缓慢分散 每次重新实例化和重新设定种子是否有危害 调用的函数?我确实读过,但没有完全理解 理解它 我试图将std::uniform\u real\u distribution dis保留为类变量,但我不断收到错误,即uniform\u real\u distribution不是s

我试图在一定范围内生成随机数。我有多个线程中的多个对象将调用这个函数,这个函数在一个单例类中,因此只有一个对象被调用。但我注意到,我的随机数更接近范围的中间值,因此,在前200次通话中,它们彼此接近,然后开始在给定范围内缓慢分散

  • 每次重新实例化和重新设定种子是否有危害 调用的函数?我确实读过,但没有完全理解 理解它
  • 我试图将
    std::uniform\u real\u distribution dis
    保留为类变量,但我不断收到错误,即
    uniform\u real\u distribution
    不是
    std::
    的成员,这是为什么
  • 我试图将
    std::shared\u ptr\u uniform\u distribution
    保留为类变量,但仍然出现错误
  • 引用随机生成器的正确方法是什么
  • 这个问题的正确解决方案是什么

  • double-getRandom(Object*foo){
    std::随机_装置rnd;
    标准:mt19937 gen(rnd());
    标准:均匀真实分布分布(0,foo->limit);
    双随机=dis(gen);
    返回随机;
    }
    
    您应该只为随机数生成器设定一次种子。除此之外,您的
    getRandom
    函数是正确的。至于如何在类上下文中使用所有这些,下面是您可以如何做到的:

    #include <random>
    
    class RNG
    {
    public:
        RNG::RNG() : gen(std::random_device()()) {} // Seeds the mt19937.
    
        double getRandom(Object* foo){  
            std::uniform_real_distribution<double> dis(0, foo->limit);
            double random = dis(gen);
            return random;
        }
    
    private:
        std::mt19937 gen;
    };
    
    #包括
    类RNG
    {
    公众:
    RNG::RNG():gen(std::random_device()){}//为mt19937种子。
    双getRandom(对象*foo){
    标准:均匀真实分布分布(0,foo->limit);
    双随机=dis(gen);
    返回随机;
    }
    私人:
    标准:mt19937 gen;
    };
    

    因此,在程序开始时,实例化一个
    RNG
    ,然后
    mt19937
    将被播种一次。然后,只要在需要随机数的时候调用同一个
    RNG

    如果要将分布作为成员变量,则必须在每次调用时创建新参数:

    #include <random>
    #include <iostream>
    
    class Object
    {
    public:
        double limit = 100.0;
    };
    
    class MyRandomGen
    {
        // typedef this for readability
        typedef typename std::uniform_real_distribution<double>::param_type param_type;
    
        std::mt19937 gen;
        std::uniform_real_distribution<double> dis;
    
    public:
        MyRandomGen(): gen(std::random_device()()) {} // seed only once
    
        double getRandom(Object* foo)
        {
            param_type range {0, foo->limit}; // new distribution parameters
            return dis(gen, range);
        }
    };
    
    
    int main()
    {
        Object o;
        MyRandomGen gen;
    
        for(auto i = 0; i < 10; ++i)
            std::cout << gen.getRandom(&o) << '\n';
    }
    

    您可以创建
    gen
    rng
    静态局部变量。这将确保随机数生成器初始化一次


    在您的函数生成器中,每次调用时都会使用新的随机种子重新初始化。将分发作为类成员应该不会有问题。将
    std::random_device
    的实例作为类成员将是一个问题(至少在许多情况下),因为它无法复制。幸运的是,您并不真正需要它的实例作为类成员,因为(如前所述)您只想调用它一次。由于其他人已经发布了他们关于更正生成器类的想法,我想我也会添加我的想法:

    class generator {
        std::uniform_real_distribution<double> dis;
        std::mt19937 gen;
    public:
        generator(double lower = 0.0, double upper = 100.0) 
            : gen(std::random_device()()), dis(lower, upper) {}
    
        double operator()() {
            return dis(gen);
        }
    };
    
    在前20名中达到0.4到95.9的数字似乎涵盖了这一范围


    另一方面,在64位编译器上,您可能希望使用
    mt19937\u 64
    而不是
    mt19937
    ,至少作为一项规则。

    目前的情况是,每次获得另一个随机数时,您都是从
    random\u设备
    中播种mt19937。在这种情况下,您也可以直接从random_设备返回数据。从随机设备进行种子设定的通常原因是对mt19937进行一次种子设定,然后在再次进行种子设定之前获取多个数字。在尝试参考
    均匀真实分布之前是否包含
    ?请参见此处的种子设定方法。只做一次@包括天顶是2。听起来好像在类定义之前没有包含
    。但您可能希望每次都重新创建发行版(因为
    foo->limit
    每次都可能不同);只需将
    gen
    设为类成员,在初始化时种子设定一次。如果您永远不想重新设定种子并希望它是自包含的,可以将其静态地放在函数中。@NeilKirk这样做包括一个假设,即只在一个上下文中使用。如果他在不同数量的上下文中使用它,输出将根据使用的数量而变化。将它作为一个实例变量,可以为每个用例提供一个随机数生成器,而不会干扰其他生成器。嗨,我想知道使用同一个种子两次(比如1010)播种会产生什么结果,这会与使用同一个数目的种子一次不同吗?@lorniper No(除非您在两个种子之间生成随机数)。@emlai谢谢,事实上我在两个种子之间生成了随机数,这可能会对随机性有害?
    rnd
    不需要是成员,因为它只在构造函数中使用。
    48.4072
    11.9905
    39.0123
    49.2113
    69.3635
    0.369986
    19.9654
    42.4251
    92.9024
    29.7522
    
    class generator {
        std::uniform_real_distribution<double> dis;
        std::mt19937 gen;
    public:
        generator(double lower = 0.0, double upper = 100.0) 
            : gen(std::random_device()()), dis(lower, upper) {}
    
        double operator()() {
            return dis(gen);
        }
    };
    
    generator g;
    
    std::generate_n(std::ostream_iterator<double>(std::cout, "\n"), 20, generator());
    
    22.832
    82.3414
    20.7805
    28.9464
    6.72104
    95.8591
    1.92738
    70.2699
    0.447961
    70.591
    0.549306
    27.9672
    10.243
    23.0606
    76.155
    67.6821
    63.7346
    20.4228
    77.9004
    39.6607