c++ srand does not give same sequences of random numbers
Asked Answered
R

2

5

I have a optimisation algorithm which uses rand() and srand(). In order to be able to test the behaviour I have set the seed to a specific number in order to get the same sequence of random numbers on different runs of the program.

#define RN rand()/(RAND_MAX+1.0)
int main(int argc, char **argv)
{
    unsigned int seed=47456536;
    srand(seed);
    // a lot of stuff including RN
}

Issue is that in different runs I get different sequence of numbers. Is that possible?

Romonaromonda answered 6/2, 2015 at 21:6 Comment(10)
"I have set the seed to a specific number in order to get the same sequence of random numbers on different runs of the program." Depends on the actual implementation of the random number generator, but guaranteed sequences of random numbers are got with seed(0) AFAIK.Honeysucker
see the comments on my answer. I think you're wrong, @πάνταῥεῖ.Leddy
I tried with 0, it did not help. I do not think it matters which seed you choose. As long as it is the same number it should give the same sequence. AFAIKRomonaromonda
@πάνταῥεῖ why would such a random restriction exist. A seed is a seed is a seed...Copepod
Reproduce the problem with a minimal amount of code. I.e., only the call to srand(), then a few calls to std::cout << rand() << "\n";. Does it still happen? E.g., ideone.com/U14x0g.Myca
As others say, either there's something extremely broken in the stdlib you are using, or there's something wrong in your "a lot of stuff" code. I presume the latter, but unless you show that code (or the minimal amount to reproduce), there's no way to be certainDesai
rand()/(RAND_MAX+1.0) may lead to differing results (especially if you're using an algorithm that compounds errors), I don't think there is any standard rquirement that this division is done in the same precision or rounds in the same direction each timeHawaiian
@indiv: Yes, I did try that. But then there is no issue. It happens only after a certain number of calls to rand() approx. 100. And I do have a massive number of call to rand().Romonaromonda
@Romonaromonda that sums it up. If it doesn't happen with the bare minimum code, then it's obviously something wrong in your code, which you haven't shownDesai
(what sums it up is the Yes, I did try that. But then there is no issue part, in case it wasn't clear)Desai
R
7

First off: Do not use rand. There are enough better alternatives.

Even the 2011 version of the C standard1 says in footnote 295:

There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient for their needs.

In case that did not convince you, please let me add some emphasis:

There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient [read: not this one] for their needs.

However, if you decide to use it against all reason, C99 7.20.2.2 and C11 7.22.2.2 both define the srand functon as follows:

(2) The srand function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand. If srand is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated. If rand is called before any calls to srand have been made, the same sequence shall be generated as when srand is first called with a seed value of 1.

(3) [...] The implementation shall behave as if no library function calls the srand function.

This means2 that either your standard library is broken, you are invoking undefined behaviour (e.g. writing to memory you should not write to) or are indeed having some other source of non-determinism. As you are surely aware, the most common sources of non-determinism are threading and reading input (keyboard, time, etc). Note that calling rand/srand from multiple threads is inherently unsafe3 beyond just the order of execution.

Since the rand random number generation facilities have only one central state, you should also be aware that libraries used by your code can modify it as well, therefore your problem may be hiding in some innocent call to a library function (excepting the standard library).

Let me also reiterate that the algorithm used by rand is not specified. Therefore, different compilers (more specifically different standard libraries) can and will produce different random numbers.

Finally, let me say again that you should not use rand if at all possible.

If there is any doubt left as to what you should be doing now, please just have a look at the following completely standards-compliant implementation of srand and rand:

#define RAND_MAX 32767
static int _rand_state = 1;
void srand(unsigned int seed) { _rand_state = (int)(seed % 32768); }
int rand() { return (++_rand_state) % 32768; }

Footnotes:

1. In case you are using linux, the man page rand(3) agrees: "on older rand() implementations, and on current implementations on different systems, the lower-order bits are much less random than the higher-order bits. Do not use this function in applications intended to be portable when good randomness is needed."

2. In combination with C99 7.20.2.1/3 or C11 7.22.2.1/3 which guarantees that the implementation behaves as if srand and rand are never called by any standard library function.

3. C11 explicitly allows data races when using these functions (C11 7.22.2.1/3 and C11 7.22.2.2/3) and C99 would do so as well if it knew the concept of threads and thread-safety.

Recommendation answered 6/2, 2015 at 21:21 Comment(3)
wow, that might have been a tiny bit off-topic, but nicely written, nevertheless. BTW: we generally use 'boost::mt19937', which is reasonably fast and really quite whiteLeddy
@MarcusMüller In my opinion, the main problem for the OP is that rand uses a central (not even thread-safe) state. It is much harder to screw this up without noticing when your state is associated with an actual generator... Nevertheless, I may have gone on a bit of a rant.....Recommendation
well, sometimes ranting is good; in this case, it illustrates a reason why OP's rand() sequence isn't static.Leddy
P
4

No, as the random number generator is defined to be deterministic given a fixed seed.

Is it possible that your "a lot of stuff including RN" might reorder things, maybe based on timing?

EDIT: "reordering": Are there external factors (time, data from files, multiple threads being scheduled etc) that might influence the order in which random numbers are requested?

EDIT: you can try to use something like Boost's RNGs; I've had excellent experience with boost::mt19937, and the fact that you can have generator "objects" eradicates the possibility that some library you're using is also getting random numbers via rand, messing up your sequence.

Pressing answered 6/2, 2015 at 21:9 Comment(9)
"No, as the random number generator is defined to be deterministic given a fixed seed." Why no? Did you read the question? The OP actually asks, why giving a fixed seed, does produce different random number sequences.Honeysucker
Would you be able to be more explicit with what "reorder things" would mean? The only call in the code to srand is that one. At some point during the execution the ith call to RN gives different result for run1 and for run2. ThanksRomonaromonda
@πάνταῥεῖ: you're wrong, I'm afraid. "Two different initializations with the same seed will generate the same succession of results in subsequent calls to rand." according to cplusplus.com/reference/cstdlib/srand . man srand gives "The srand() function sets its argument as the seed for a new sequence of pseudo-random integers to be returned by rand(). These sequences are repeatable by calling srand() with the same seed value."Leddy
The documentation of the srand function clearly states that what Cristina is witnessing should never happen. Either there is a very serious bug on such a crucial method in the implementation of the C library that Cristina is using, or Cristina is making a mistake. Which of the two is more likely?Belleslettres
@MarcusMüller "Whoever downvoted me: why??" I'm not going to disclose my downvotes :-P ...Honeysucker
@πάνταῥεῖ: I think you stand corrected, so why downvote my answer?Leddy
I highly doubt myself that there is a bug in the library. More likely I'm making a mistake or there is a factor of data racing that I did not notice. There is no software threading and the hardware threading, no data from files. My biggest surprise is that the sequence is the same until a certain point and then it becomes different. That is why I wanted some other opinions on it.Romonaromonda
Try logging the number of calls to rand with different seeds. If you get a different number of calls for different seeds then that's likely your problem. We've used rand with a specific seed for many things, and tracked down many bugs because it was sometimes being called conditionally which throws the whole sequence off.Xenogenesis
@Romonaromonda you should really edit your question to add the minimum code where this is reproducible if you want to know what's wrong. With the code you provided, this is not reproducible at all so there's no way for us to help.Desai

© 2022 - 2024 — McMap. All rights reserved.