Calling srand each time before generating random numbers make it more or less random?

I need to generate random numbers many times (retrieving elements from different arrays) and it seems the following code produce results that follow a pattern:

1
2
3
4
5
srand((unsigned int)time(0));
infoGroupOne = rand() % 34;
infoGroupTwo = rand() % 34;
extraInfoOne = rand() % 5;
extraInfoTwo = rand() % 5;


I also realize that two of the arrays are short. Calling srand in the beginning of the function didn't really seem to make it better, perhaps even more obvious patterns.

Edit: I forgot to add that I used this_thread::sleep_for(chrono::milliseconds(2000)); before each iteration, so I actually didn't get the same numbers in any of the cases.
Last edited on
Well if you're calling srand() at the beginning of a function other than main(), you're doing it wrong.

1
2
3
4
5
6
7
8
9
10
11
12
13
void function() {
    srand((unsigned int)time(0));
    infoGroupOne = rand() % 34;
    infoGroupTwo = rand() % 34;
    extraInfoOne = rand() % 5;
    extraInfoTwo = rand() % 5;
}

int main ( ) {
    for ( int i = 0 ; i < 10 ; i++ ) {
        function();
    }
}

As far as this code is concerned, the result of time(0) is a constant. Your CPU can execute billions of instructions in between the moments when time(0) ticks to a new value.

What you should do is only call srand() ONCE.
1
2
3
4
5
6
7
8
9
10
11
12
13
void function() {
    infoGroupOne = rand() % 34;
    infoGroupTwo = rand() % 34;
    extraInfoOne = rand() % 5;
    extraInfoTwo = rand() % 5;
}

int main ( ) {
    srand((unsigned int)time(0));
    for ( int i = 0 ; i < 10 ; i++ ) {
        function();
    }
}

Now you should have more meaningful randomness in function().
Everything Salem said is true, and answers your immediate question. This is good; well done Salem.

There is, as is often the case, also a bigger context here. In effect, now that your question has been answered, we can help you stretch your skills by going deeper.

That bigger context is: don't use rand() to generate your "random" numbers. It's bad. Very bad. Don't do it.

Here is STL delivering a very understandable talk all about it: https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
Last edited on
Lets make a simpler rand():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constexpr int N = 5;
int wheel[N] {7, 2, 4, 9, 5};
int current = 0;

void srand( int pos ) {
  current = pos % N;  
}

int rand() {
  int result = wheel[current];
  ++current;
  current %= N; // current is always in [0..N)
  return result;
}

If we call our rand() 4 times, then we will get {7, 2, 4, 9}

If we call srand(2) and then rand() 4 times, then we will get {4, 9, 5, 7}

If we call srand(time(0)) before each call to rand() and the time(0) returns 3 every time because our program is fast, then we will get {9, 9, 9, 9}


The "wheel" behind the C Standard Library's rand() is larger, but:
1
2
3
4
5
6
7
void function() {
    srand((unsigned int)time(0));
    infoGroupOne = rand() % 34;
    infoGroupTwo = rand() % 34;
    extraInfoOne = rand() % 5;
    extraInfoTwo = rand() % 5;
}

... will get exact same four consecutive numbers from the "wheel" on every call of the 'function' (unless calls are far from each other in time).


Easy to test too:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <cstdlib>
#include <ctime>

void function() {
    srand((unsigned int)time(0));
    int a = rand() % 34;
    int b = rand() % 34;
    int c = rand() % 5;
    int d = rand() % 5;
    std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n';
}

int main ( ) {
    for ( int i = 0 ; i < 10 ; ++i ) {
        function();
    }
}

4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1
4 15 4 1

vs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <cstdlib>
#include <ctime>

void function() {
    int a = rand() % 34;
    int b = rand() % 34;
    int c = rand() % 5;
    int d = rand() % 5;
    std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n';
}

int main ( ) {
    srand((unsigned int)time(0));
    for ( int i = 0 ; i < 10 ; ++i ) {
        function();
    }
}

24 22 1 0
19 27 1 3
5 13 1 2
26 25 0 2
9 29 2 0
0 31 1 2
14 2 0 1
28 30 3 0
18 13 0 1
6 23 2 0



As said, if you are about to learn C++, then do learn the use of <random> and skip the <cstdlib> for now.
See: http://www.cplusplus.com/reference/random/
As others have pointed out using <random> to generate random numbers in C++ is much better than using <cstdlib>. It is also better to use <chrono> for time-based seeds, skip using <ctime> as well.

The code needed to replicate time(0), and seed one of the C++ pseudo-random number engines looks complicated:

1
2
unsigned seed= std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine gen(seed);

or

std::default_random_engine gen(std::chrono::system_clock::now().time_since_epoch().count());

<random> also includes more precise ways to obtain a range of random numbers, rand() and % have bias errors. Certain numbers in the range have a greater chance of being selected than others.
Furry Guy, why is <chrono> better than <ctime> for the seeds?
@jsmithplus, Furry Guy's method yields the time since the epoch in nanoseconds (and overflows the unsigned int if it's only 32-bits, but that's not much of a problem).

time() from <ctime> returns only seconds. However, C11 has timespec to retrieve nanoseconds.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <chrono>
#include <ctime>

int main() {
    std::cout << "chrono\n";
    for (int i = 0; i < 5; ++i) {
        auto seed = std::chrono::system_clock::now().time_since_epoch().count();
        std::cout << seed << '\n';
    }

    std::cout << "time\n";
    for (int i = 0; i < 5; ++i) {
        auto tim = time(nullptr);
        std::cout << tim << '\n';
    }

    std::cout << "timespec\n";
    for (int i = 0; i < 5; ++i) {
        struct timespec ts;
        timespec_get(&ts, TIME_UTC);
        std::cout << ts.tv_nsec << '\n';
    }
}

Here’s a good thread I found on weighing between generators if ya need it 😜:
https://stackoverflow.com/questions/16536617/random-engine-differences
Or obviously just go to the <random> section in the reference page on this site like keskiverto said.
Last edited on
So this would be an equivalent solution with <random>?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	int seed = unsigned int(chrono::system_clock::now().time_since_epoch().count());
	
	default_random_engine randEngineOne(seed);
	uniform_int_distribution<int> distOne(0, 33;
	auto randLong = bind(distOne, randEngineOne);
	
	default_random_engine randEngineTwo(seed);
	uniform_int_distribution<int> distTwo(0, 4);
	auto randShort = bind(distTwo, randEngineTwo);
	
	
	infoGroupOne = randLong();
	infoGroupTwo = randLong();
	extraInfoOne = randShort();
	extraInfoTwo = randShort();


I'm actually geting this warning: Warning C6262 Function uses '20036' bytes of stack: exceeds /analyze:stacksize '16384'. Consider moving some data to heap.
you pushed over your limit. There is usually a compiler flag to increase the stack. It could be a debug problem and that release build is not using so much stack, but you would be on the edge in that case. That stack is TINY ... live a little, go ahead an allocate a whole megabyte.
Last edited on
Consider writing a small function. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <random>
#include <chrono>
#include <stdexcept>

int rand_integer( int minv, int maxv )
{
    static const auto seed = std::random_device{}() ;
    // or on implementations which do not have a meaningful random device (MinGW)
    // static const auto seed = std::chrono::system_clock::now().time_since_epoch().count() ;

    static std::default_random_engine engine(seed) ;
    static std::uniform_int_distribution<int> distrib ;

    if( minv > maxv ) throw std::invalid_argument( "bad params" ) ;

    distrib.param( std::uniform_int_distribution<int>::param_type{ minv, maxv } ) ;
    return distrib(engine) ;
}
@JLBorges This seem to go against previous advice, not to generate a new seed every time it generates a new random number? I mean that you should call/feed the srand function in the main function and then generate the random number in another.

It generates the seed (and initialises the random engine) only once; the first time the function is called.
See https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
Topic archived. No new replies allowed.