-5

C++11 Introduced the class that allows for generating very random numbers, it also creates an even distribution of random numbers. There is also implementation to generate a seed (a number used to make the Random Number Generator more random).

I am trying to make a function that generates a random number between min and max but I am having trouble. The function only generates the seeds and the random number once. When I call the function in other words it will keep giving me the same number.

Below is the code, I try to generate a bunch of seeds, pick one of them randomly, use that seed for the RNG and finaly produce a random number.

int Utils::GenerateSuperRandomNum(int min, int max)
{
    //Seed a the RNG
    int randNum;
    int randIndex;
    seed_seq seq{ 1, 2, 3, 4, 5 };
    vector<int> seeds(5 * max);
    uniform_int_distribution<int> rngDistribution(min, max);    //Generates number in the range min to max.

    //Generate our seed numbers.
    seq.generate(seeds.begin(), seeds.end());

    //Generate random index bewteen 0 and size - 1.
    srand(seeds.at(0));
    randIndex = rand() % seeds.size(); 

    //Seed the RNG with a random seed from our vector.
    mt19937 rngGenerator(seeds.at(randIndex)); 

    //Get a random number.
    randNum = rngDistribution(rngGenerator);

    return randNum;
}
Katianie
  • 589
  • 1
  • 9
  • 38
  • 4
    If you keep reseeding your random generator with the same seed, you will keep getting the same result. – StarPilot Mar 19 '15 at 22:44
  • 4
    Just why? Btw, your function takes does not read any external variable beside the two argument you provide... ergo the inputs entirely determine the outputs – sbabbi Mar 19 '15 at 22:44
  • 1
    You should use `std::random_device` to create your seed. See [here](http://stackoverflow.com/questions/19665818/best-way-to-generate-random-numbers-using-c11-random-library/19666713#19666713) for an actual example of how this code should look... – Bill Lynch Mar 19 '15 at 22:46
  • If you want it super random, don't use `rand()`. – Emil Laine Mar 19 '15 at 22:46
  • 3
    FYI, `rand() % seeds.size()` will **NOT** (in general) generate a number uniformly-at-random. – Nicu Stiurca Mar 19 '15 at 22:46
  • @Katianie I highly recommend you try to grok how [_pseudo_-random number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) work. Sorry that I don't have the inclination to try to explain it to you in a way that illuminates what is wrong with your approach. – Nicu Stiurca Mar 19 '15 at 23:14
  • @BillLynch I read it and it confirmed what I said, seeds are used to make the RNG select a more pseudo random number...... – Katianie Mar 19 '15 at 23:18
  • 1
    You should only seed once and reuse the same generator across multiple calls to `GenerateSuperRandomNum()` (i.e., make `rngGenerator` static or a member of `Utils`, if it is a class). – Julian Mar 19 '15 at 23:18
  • The way to use a pseudo-random number generator is to first pick a seed (by some method), use that to seed the generator *once*, and then generate arbitrarily many pseudo-random numbers. PRNGs are *designed* to work this way. Seeding it more than once will not help, and will very probably hurt. – Keith Thompson Mar 19 '15 at 23:23
  • 2
    To add to my earlier comment, `seq.generate(seeds.begin(), seeds.end());` will always generate the same sequence, so `seeds.at(0)` will always return the same value, hence `srand` always receives the same value. Likewise `randIndex` will always have the same value. Two identical generator instances seeded with the same number will produce the same series of results across their lifetimes. I just wanted to explain why your solution isn't working. See @Mooing Duck's answer for a better solution. – Julian Mar 19 '15 at 23:25

3 Answers3

6
seed_seq seq{ 1, 2, 3, 4, 5 };
vector<int> seeds(5 * max);
uniform_int_distribution<int> rngDistribution(min, max);    //Generates number in the range min to max.

//Generate our seed numbers.
seq.generate(seeds.begin(), seeds.end());

seq is always fed the same input {1,2,3,4,5} so always has the same state. Since it has the same state, seeds.at(0) is always the same value.

//Generate random index bewteen 0 and size - 1.
srand(seeds.at(0));

Since srand is seeded with that same value every time, it to starts with the same state every time. Since it receives the same value every time, it always starts with the same state. The same state that rand uses.

randIndex = rand() % seeds.size(); 

Since rand always has the same state as per the srand, it will always generate the same first number every single time.

 mt19937 rngGenerator(seeds.at(randIndex)); 

Since randIndex is always the same value, then seeds.at(randIndex) is always the same value. Since rngGenerator is always seeded with the same value, it always has the same state.

randNum = rngDistribution(rngGenerator);

Since rngDistribution always has the same state, it always produces the same value.

This is obviously a problem. The simple fix is to seed based on the CPU temperature, or the time, or some other value that changes often.


Basically, you've seriously overthought this. It's designed to be used like this:
int Utils::GenerateSuperRandomNum(int min, int max) {
    static mt19937 rngGenerator(std::random_device{}());
    std::uniform_int_distribution<int> rngDistribution(min, max);
    return rngDistribution(rngGenerator);
}

std::random_device{}() generates a vaguely randomish number based on magic, hopefully hardware, like maybe the CPU tempurature or something. It can be slow or have other issues, so you should only use it once per program. Namely, to seed a faster/better generator.

static mt19937 rngGenerator( creates a single global generator, which is seeded the first time the function is called, and is never seeded again. This is perfect, because we want it to be initialized once, and then just do it's magic from then on. The usage of other generators like rand don't add any entropy, so don't do that. We also don't want to re-seed it, as that might accidentally reduce randomness, rather than increase it.

std::uniform_int_distribution<int> rngDistribution(min, max); and rngDistribution(rngGenerator) you seem to understand. They use the generator to give random numbers in that distribution. Done deal.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
1

A seed does not make a (pseudo-)random number generator more random. It provides a starting point for generating a reproducible sequence of random numbers.

Which means, if you provide the exact same seed, you'll get the exact same results.

Matthew Moss
  • 1,258
  • 7
  • 16
  • 7
    OP is basically implementing a convoluted version of [this](https://www.xkcd.com/221/) – Nicu Stiurca Mar 19 '15 at 22:48
  • @SchighSchagh Much truth. – Matthew Moss Mar 19 '15 at 22:51
  • Because you use the same seed, you will generate the same number. Pretty simple. – Matthew Moss Mar 19 '15 at 23:16
  • @Katianie: People are not going to be inclined to help you if you shout at them and insult them. (I presume "neckbeard" is intended as an insult.) – Keith Thompson Mar 19 '15 at 23:19
  • @MatthewMoss It should be noted that guessing what the seed was becomes harder with a wider range of seeds, which is almost the same thing as making the generator more random if you encounter many generators in the wild and consider your stream a set of such generators. – Mikhail Mar 19 '15 at 23:23
  • @Mikhail It's trivial to save the seed off into memory somewhere... no guessing required. Then, if you have to debug a problem related to the sequence, reseed with the same seed saved earlier. Doesn't make it more random. – Matthew Moss Mar 19 '15 at 23:24
  • 1
    @Katianie Any PRNG will generate new numbers *provided you don't keep reseeding it with the same seed at each call.* I made no insults; I explained in short why it didn't work. You refuse to listen. – Matthew Moss Mar 19 '15 at 23:25
0

Making a random number generator more "random" by using it to generate it's own seed is a bit like trying to lift yourself up by pulling on your boot straps. If this is just for fun the time is a sufficiently random seed, if you are doing super spy crypto a h/w device that provides true random events is what you need.

You could try using this service, I don't know if it is valid or just the NSA trying to trick you. https://www.random.org

DaveB
  • 342
  • 1
  • 9
  • @Katianie, the new number is not "more random" than your previous one. To compute randomness, you need to compute the entropy of the source. In this case, the RNG is pseudo-random, i.e. of entropy 0, so there is no true randomness. Everything is pre-determined as a function of the seed. – vsoftco Mar 19 '15 at 23:20
  • a pseudo random number generator generates a list of numbers that look random, but if you start reading at the same place in the list you get the exact same sequence of numbers. The seed is just where you start reading in the list, starting at a different place in the list doesn't make the list any more or less random. – DaveB Mar 19 '15 at 23:20
  • @DaveB supposedly `/dev/random` in Linux has non-zero entropy, and most implementations of `std::random_device` use internally `/dev/random`, so seeding a RNG via `std::random_device` should give you at least a seed that is random. – vsoftco Mar 19 '15 at 23:25
  • @vsoftco yes /dev/random is, I believe, a h/w device that collects entropy. My understanding is there are some limitations in using it as a RNG, it can get used up pretty quickly. Using it to generate a seed for a PRNG would be a good idea, and it would make it harder to guess the seed. But you are still using a PRNG and the numbers you get are still not truly random. This question has a good discussion on this topic http://stackoverflow.com/questions/13779441/resetting-pseudo-random-number-generator-seed-multiple-times – DaveB Mar 22 '15 at 18:02