2

I applied the random number generator to my code although the first number generated doesn't change when I run the code second or the third time. The other numbers change however and the issue is only on the first value. I'm using code blocks; Cygwin GCC compiler (c++ 17). Seeding using time.

#include <iostream> 
#include <random>
#include <ctime>
    
int main()
{
    std::default_random_engine randomGenerator(time(0));
    std::uniform_int_distribution randomNumber(1, 20);
    int a, b, c;
    a = randomNumber(randomGenerator); 
    b = randomNumber(randomGenerator); 
    c = randomNumber(randomGenerator);
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

    return 0;
}

In such a case when I run the code the first time it may produce a result like a = 4, b = 5, c = 9. The second and further time (a) remains 4 but (b) and (c) keep changing.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
Mouse
  • 35
  • 5
  • Technically, going off what you've said, you could write `int dummy = randomNumber(randomGenerator);` immediately after you've declared `randomNumber`. Although I'm sure you want an explanation. – Elliott Jul 19 '22 at 13:52
  • I've been using a dummy value to skip the first output and make the second value act as the first. It has been working although I wanted to use it in my constructor and it's picking up only the first value. Unless you meant otherwise. – Mouse Jul 19 '22 at 13:56
  • Use a better PRNG, and seed it better. – sweenish Jul 19 '22 at 13:58
  • 3
    Don't use `std::default_random_engine`. Use a `std::mt19937` instead. – NathanOliver Jul 19 '22 at 14:00
  • [Related](https://stackoverflow.com/questions/50662280/c-need-a-good-technique-for-seeding-rand-that-does-not-use-time) – PaulMcKenzie Jul 19 '22 at 14:03
  • libstdc++ appears to use [`minstd_rand0`](https://en.cppreference.com/w/cpp/numeric/random/linear_congruential_engine) for `std::default_random_engine` which isn't of the best quality. Even using `minstd_rand0` with other standard libraries doesn't seem to reproduce this problem though: https://godbolt.org/z/xz4W4hc63 – Alan Birtles Jul 19 '22 at 14:19

1 Answers1

7

Per my comment, the std::mt19937 is the main PRNG you should consider. It's the best one provided in <random>. You should also seed it better. Here I use std::random_device.

Some people will moan about how std::random_device falls back to a deterministic seed when a source of true random data can't be found, but that's pretty rare outside of low-level embedded stuff.

#include <iostream>
#include <random>

int main() {
  std::mt19937 randomGenerator(std::random_device{}());
  std::uniform_int_distribution randomNumber(1, 20);

  for (int i = 0; i < 3; ++i) {
    std::cout << randomNumber(randomGenerator) << ' ';
  }
  std::cout << '\n';

  return 0;
}

Output:

~/tmp 
❯ ./a.out 
8 2 16 

~/tmp 
❯ ./a.out
7 12 14 

~/tmp 
❯ ./a.out
8 12 4 

~/tmp 
❯ ./a.out
18 8 7

Here we see four runs that are pretty distinct. Because your range is small, you'll see patterns pop up every now and again. There are other areas of improvement, notably providing a more robust seed to the PRNG, but for a toy program, this suffices.

sweenish
  • 4,793
  • 3
  • 12
  • 23