All objects made through constructor have the same vectors

房东的猫 提交于 2021-01-28 23:55:30

问题


I'm new to C++ and I am trying to create a basic genetic algorithm. I created a Chromosome class and want to create a Society class that generates a vector of these Chromosomes with randomly generated "genes". Genes being the vector in the Chromosome that holds values of 0 or 1. I was testing out the Chromosome constructor, and all of the objects have the same gene vectors. How can I make the constructor generate random values? I have included code below. Any other coding practice or optimization tips would also be extremely appreciated.

Source.cpp

#include "Chromosome.h"
#include "Society.h"

using namespace std;

int main()
{
    Chromosome demo = Chromosome::Chromosome();
    Chromosome demo2 = Chromosome::Chromosome();
    return 1;
}

Chromosome.h

#pragma once
#include <vector>
using namespace std;

class Chromosome
{
private:
    int fitness;
    vector<int> genes;

public:
    Chromosome();

    void generateGenes();

    int calculateFitness(),
        getFitness();

    vector<int> getGenes();
    void setGenes(vector<int> child);
};

Chromosome.cpp

#include "Chromosome.h"
#include <cstdlib>
#include <ctime> 
#include <numeric>
using namespace std;

Chromosome::Chromosome()
{
    generateGenes();
    Chromosome::fitness = calculateFitness();
}

void Chromosome::generateGenes()
{
    srand(time(NULL));
    for (unsigned i = 0; i < 10; i++)
    {
        unsigned chance = rand() % 5;
        Chromosome::genes.push_back((!chance)? 1 : 0);
    }
}

int Chromosome::calculateFitness()
{
    int sum = 0;
    for (unsigned i = 0; i < Chromosome::genes.size(); i++)
    {
        sum += Chromosome::genes[i];
    }
    return sum;
}

int Chromosome::getFitness()
{
    return Chromosome::fitness;
}

vector<int> Chromosome::getGenes()
{
    return Chromosome::genes;
}

void Chromosome::setGenes(vector<int> child)
{
    Chromosome::genes = child;
}

回答1:


You seed the random number generator with the same value time(NULL). Two calls after eachother will return the same time_t. You'll generate one set of random numbers first, then reset the random number generator and generate them again.

Only call srand() once during the whole program run.

Also, use <random> instead to get better/faster random number generators.

Instead of rand() % 5; using <random>:

#include <random>

// A function to return a random number generator.
inline std::mt19937& generator() {
    // the generator will only be seeded once since it's static
    static std::mt19937 gen(std::random_device{}());
    return gen;
}

// A function to generate unsigned int:s in the range [min, max]
int my_rand(unsigned  min, unsigned  max) {
    std::uniform_int_distribution<unsigned > dist(min, max);
    return dist(generator());
}

Then call it:

unsigned chance = my_rand(0, 4);



回答2:


Your problem is the use of rand & srand in a C++ program.

srand(time(NULL));
unsigned chance = rand() % 5;

in this implementation, rand might return multiple numbers that will give you the same final result. for example: 19, 24, 190214, 49789, 1645879, 15623454, 4, 156489719, 1645234, 152349, ...

There are different ways of generate random numbers in C++, this one isn't recommended due to bad results.

One (of many) good ways to generate random, using "pseudo-random" in C++:

void Chromosome::generateGenes()
{
    // Initialize random
    std::random_device rd;  // Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> dis(0, 5);

    for (unsigned i = 0; i < 10; i++)
    {
        // Use random: dis(gen);
        unsigned chance = dis(gen);
        Chromosome::genes.push_back((!chance)? 1 : 0);
    }
}

Include:

#include <random>

Right note by @TedLyngmo: Every time that function will be called (in your case, in every object creation in the constructor call), this code will make you generate a new random seed (In 'Initialize random' section). In more progress cases, or as the program grows, it is highly recommended to extract this initialize to another function (and maybe to a new class object for modular programming reason). In this response I demonstrated the general syntax of using this type of random in your case.

Read about:

Pseudo-random number generation

Uniform Distribution

Thanks to @M.M: How to succinctly, portably, and thoroughly seed the mt19937 PRNG?



来源:https://stackoverflow.com/questions/60216236/all-objects-made-through-constructor-have-the-same-vectors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!