C++ 为什么这4个不同的随机数生成器函数会产生相同的数字序列?

C++ 为什么这4个不同的随机数生成器函数会产生相同的数字序列?,c++,c++11,random,C++,C++11,Random,我正在调试的神经进化程序不会在每次调用时都产生随机值。在程序中,使用以下语句初始化网络对象的向量: vector<Network> population(POPULATION_SIZE, Network(sizes, inputCount)); 矢量总体(总体大小、网络大小、输入计数); 为什么我认为程序不会收敛到一个最优解,是因为,前100个人总是一样的。以这种方式初始化网络时,连接权重和神经元偏差(每个)用以下类函数初始化: double Network::randDoubl

我正在调试的神经进化程序不会在每次调用时都产生随机值。在程序中,使用以下语句初始化网络对象的向量:

vector<Network> population(POPULATION_SIZE, Network(sizes, inputCount));
矢量总体(总体大小、网络大小、输入计数);
为什么我认为程序不会收敛到一个最优解,是因为,前100个人总是一样的。以这种方式初始化网络时,连接权重和神经元偏差(每个)用以下类函数初始化:

double Network::randDouble(double low, double high) {
    /*default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
    uniform_real_distribution<double> distribution(low, high);
    return distribution(generator);*/

    /*srand(time(NULL));
    double temp;
    if (low > high) {
        temp = low;
        low = high;
        high = temp;
    }
    temp = (rand() / (static_cast<double>(RAND_MAX) + 1.0)) * (high - low) + low;
    return temp;*/

    /*mt19937 rgn(std::chrono::system_clock::now().time_since_epoch().count());
    uniform_real_distribution<double> gen(low, high);
    return gen(rgn);*/

    default_random_engine rd;
    uniform_real_distribution<double> gen(low, high);
    auto val = std::bind(gen, rd);
    return val();
}
double Network::randDouble(双低双高){
/*默认的随机引擎生成器(std::chrono::system_clock::now();
均匀实分布(低、高);
回流分配(发电机)*/
/*srand(时间(空));
双温;
如果(低>高){
温度=低;
低=高;
高=温度;
}
温度=(兰特()/(静态铸造(兰特最大值)+1.0))*(高-低)+低;
返回温度*/
/*mt19937 rgn(标准::时钟::系统时钟::现在();
均匀真实分布发电机(低、高);
返回发电机(rgn)*/
默认随机引擎rd;
均匀真实分布发电机(低、高);
自动val=std::绑定(gen,rd);
返回val();
}
3个注释掉的部分是以前尝试的生成所需功能的方法。在每种情况下,它们为每个网络生成相同的数字(不同于1个权重到另一个,但不是1个网络到另一个)。尝试的方法基于以下答案:

  • 此外,第二种方法在有或没有种子的情况下产生相同的结果。我一定错过了什么


    另一个,尽管可能与此无关的问题是,使用此函数的函数可能会使用OpenMP进行并行化,并且当并行调用时,结果可能是相同的。

    您的问题是每次生成数字时都在初始化(播种)随机生成器。在简单的
    srand()
    情况下,您应该在程序启动期间只调用一次
    srand()
    ,然后在每次需要一个号码时调用
    rand()
    。在更复杂的情况下,应该只构造一次生成器(在整个程序运行中),并根据需要多次使用它。

    C++11标准随机数引擎(以及大多数其他随机生成器)实际上是伪随机数序列的生成器。伪随机意味着序列是可重复的。每次给定的伪随机生成器使用相同的种子进行播种时,它将始终生成相同的序列。(但这并不完全是代码中发生的事情。请继续阅读。)

    在C++11中,种子设定发生在随机数引擎实例化时。这意味着您需要为每个伪随机序列实例化引擎一次。您的代码在每次调用Network::randDouble()方法时对引擎进行种子设定的方式,不能期望得到引擎设计用来产生的伪随机序列。相反,您将从对系统时钟的调用所播种的序列中获得一系列第一个数字:。。。或者time()方法

    调用system_clock::now().time_since_epoch().count()返回整数周期的时间。period指的是模板类std::chrono::duration的专门化,该类由time_自_epoch()返回。默认情况下,周期可能为秒,这可以解释为什么所有网络对象在每次调用Network::randDouble()时都获得相同的种子

    如果希望每个网络具有不同的序列,最好在网络类的c-tor中实例化伪随机引擎,并为网络类的每个对象使用不同的种子对其进行种子设定。这意味着引擎或指向引擎对象的指针应该是类的成员

    例如:

    class Network {
    
    ...
    protected:
        mt19937 rd;
    ...
    }
    
    Network::Network(int rndseed) :
        rd(rndseed)
    {
    ...
    }
    
    double Network::randDouble(double low, double high) {
    
        uniform_real_distribution<double> gen(low, high);
        auto val = gen(rd);
        return val;
    }
    
    类网络{
    ...
    受保护的:
    mt19937路;
    ...
    }
    网络::网络(int rndseed):
    rd(rndseed)
    {
    ...
    }
    双网络::randDouble(双低,双高){
    均匀真实分布发电机(低、高);
    自动值=发电机(rd);
    返回val;
    }
    

    为了确保伪随机引擎的每个实例都得到不同的种子,您可以使用一些简单的方法,如后续整数。如果要使用系统时钟,即使使用std::chrono::high_resolution_clock,也很难保证每次种子都是不同的。CPU的速度非常快,您需要特别注意确保您正在使用的时钟计数在两次调用之间实际发生了变化。

    如果在main中调用,
    srand()
    ,是否对类中的函数有效?@DerekSmith:是的。我发现了问题。创建网络向量时,它必须只创建了100个副本。这是通过简单地用一个新的网络返回所需的100个变量来解决的。在所有3个变量前面加上“static”前缀。