I am testing the RNG code as mentioned in link (fortran 77 code):
https://www.cisl.ucar.edu/zine/96/spring/articles/3.random-6.html
which applies the Park & Miller algorithm.
the function call of the program is
call srand(seed)
x=rand()
However the program does not seem to respond to the seeding by srand(), i.e., the x-value is unaffected by the initial seeding, and always equal to ~0.218. I suspect that this has to do with the definition of the common block and data block, as the value of x is equivalent to putting the seed as 123456789, which is the initialization value defined in the datablock.
Any ideas?
I am compiling with gfortran.
Ok, the problem is that the original srand and rand may be called. I renamed functions to srand2 and rand2 and everything start to work as expected.
For seed = 1 the result is 7.82636926E-06 and for seed = 2 the result is 1.56527385E-05. Checked it in gfortran and in Intel's fortran.
Related
I'm implementing an algorithm. Because calculations takes time, and I need to repeat them multiple times, I'm saving to output file seed values as well. The idea was that I could repeat same instance of a program if I'll need to get more info about what was happening (like additional values, some percentage, anything that will not mess in the algorithm itself).
Unfortunately, even though I thought everything worked as intended, about 20% of the seeded instances gave different values in at least one of the outputted values.
My question is - what type of changes in the code affects how srand() / rand() works in C++? Each class is compiled separately and all are linked together at the end. Can I implement functions and everything will be fine? Does it break only when I change the size of any class in the program by adding/removing class fields? Is it connected with heap/stack allocation?
Until now, I thought that if I seed srand() I will have same order of rand() values no matter what (eg. for srand(123) I'll always get first rand() == 5, second rand() == 8 etc.). And I can break it only when I'll put more rand() calls in between.
I hope you could find where I'm thinking wrong, or you could link something that will help me.
Cheers
mrozo
Your understanding about srand is correct: seeding with a specific value should be enough to generate a reproducible sequence of random numbers. You should debug your application to discover why it behaves in a non-reproducible way.
One reason for such behavior is a race condition on the hidden RNG state. Quoting from the C++ rand wiki:
It is implementation-defined whether rand() is thread-safe.
...
It is recommended to use C++11's random number generation facilities to replace rand().
I have been learning recently how to program games in c++ from a beginner book, and i reached a lesson where i have to make a game in where i have to guess the computer's random picked number, and i have to use this line of code:
srand(static_cast<unsigned int>(time(0)));
variable=rand();
I obviously use iostream cstdlib and ctime.I don't really understand how this works.How is it picking the time and date, and by what rules is it converting into an unsigned int. Basically, how those functions work.
Thank you!
1. About time()
time (or better std::time in C++) is a function that returns some integer or floating point number that represents the current time in some way.
Which arithmetic type it actually returns and how it represents the current time is unspecified, however, most commonly you will get some integer type that holds the seconds since begin of the Unix epoch.
2. About srand()
srand is a function that uses its argument (which is of type unsigned int), the so called seed, to set the internal state of the pseudo number generator rand. When I write random in the rest of this answer, read pseudo random.
Using a different seed will in general result in a different sequence of random numbers produced by subsequent calls to rand, while using the same seed again will result in the exactly same sequence of random numbers.
3. Using time() to seed rand()
If we do not want to get the same random numbers every time we run the program, we need some seed that is different on each run. The current time is a widely used source for such a seed as it changes constantly.
This integer (or whatever else time returned) representing the current time is now converted to unsigned int with a static_cast. This explicit cast is not actually needed as all arithmetic types convert to unsigned int implicitly, but the cast may silence some warnings. As time goes by, we can expect the resulting unsigned int and thus the sequence of random numbers produced by rand to change.
4. Pitfalls
If, as is common, time returns the number of seconds since the beginning of the Unix epoch, there are three important things to note:
The sequence you produce will be different only if at least a second has passed between two invocations.
Depending on the actual implementation, the resulting sequences may start of kind of similar if the time points used to seed rand are close to each other (compared to time since Epoch). Afaik, this is the case in MSVC's implementation. If that is problematic, just discard the first couple of hundred or thousand values of the sequence. (As I have learned by now, this does not really help much for poor RNGs as commonly used for rand. So if that is problematic, use <random> as described below.)
Your numbers are not very random in the end: If someone knows when your call to srand occurred, they can derive the entire sequence of random numbers from that. This has actually led to a decryption tool for a ransom ware that used srand(time(0)) to generate its "random" encryption key.
Also, the sequence generated by rand tends to have poor statistical properties even if the seed was good. For a toy program like yours, that is probably fine, however, for real world use, one should be aware of that.
5. The new <random>
C++11 introduced new random number facilities that are in many ways superior to the old rand based stuff. They provided in the standard header <random>. It includes std::random_device which provides a way to get actually random seeds, powerful pseudo random number generators like std::mt19937 and facilities to map the resulting random sequences to integer or float ranges without introducing unnecessary bias.
Here is an example how to randomly roll a die in C++11:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
(Code from cppr) Note: std::random_device does not work properly with MinGW, at least in the version (Nuwen MinGW5.3) I tested!
It should also be noted that the state space of a mt19937 is much larger than the 32 bit we (commonly) get out of a single call to random_device. Again, this will most likely not matter for toy programs and homework, but for reference: Here is my attempt to properly seed the entire state space, plus some helpful suggestions in the answers.
If you are interested in more details about rand vs <random>, this is an interesting watch.
First line:
srand() is a pseudo-random number generator. In your case it is initialized with the current time (execution time) on your system.
Second line:
After the pseudo-random number generator is configured, you can retrieve random numbers by calling rand().
we are in the context of a lua script which uses some C/C++ functions exported to be used with lua.
In lua, we have
math.randomseed(12) // 12 for example
for i=0, 10 do
c++function()
print(math.random())
end
the output is always the same number.
When i saw the cause, i found that in the c++_function, there is an srand(0) and some calls to the rand() function.
So our math.randomseed(12) will have no effect, and we will in each iteration have srand(0), the rand() call, and after that the math.random() call(which just call the C rand() function).
and because we are giving always the same seed, we have always the same sequence generated.
The question is, is there a solution to make srand(x) limited to a specific scope ? so the rand() call in c++_function will use the seed 0, and when we return back to lua, the math.random() uses the math.randomseed(x).
If no, any one have a suggestion ?
Thank you
Unfortunately, srand does not return its current seed. Nevertheless, you can fake it. Try this:
function call_c_function()
local s=math.random(1,2^30)
c++function()
math.randomseed(s)
end
for i=0, 10 do
call_c_function()
print(math.random())
end
Just make sure that you don't call math.randomseed before each call to math.random, but only after calling c++function, as above.
You probably will not be able to limit the scope of srand() to affect only your invocation of math.random().
I'd suggest to use a random number generator that is independent of the built-in. See Generating uniform random numbers in Lua for an example.
Okay I'm starting to lose my mind. All I want to do is random a number between 0 and 410, and according to this page, my code should do that. And since I want a random number and not a pseudo-random number, I'm using srand() as well, in a way that e.g. this thread told me to do. But this isn't working. All I get is a number that is depending on how long it was since my last execution. If I e.g. execute it again as fast as I can, the number is usually 6 numbers higher than the last number, and if I wait longer, it's higher, etc. When it reaches 410 it goes back to 0 and begins all over again. What am I missing?
Edit: And oh, if I remove the srand(time(NULL)); line I just get the same number (41) every time I run the program. That's not even pseudo random, that's just a static number. Just copying the first line of code from the article I linked to above still gives me number 41 all the time. Am I the star in a sequel to "The Number 23", or have I missed something?
int main(void) {
srand(time(NULL));
int number = rand() % 410;
std::cout << number << std::endl;
system("pause");
}
That is what you get for using deprecated random number generation.
rand produces a fixed sequence of numbers (which by itself is fine), and does that very, very badly.
You tell rand via srand where in the sequence to start. Since your "starting point" (called seed btw) depends on the number of seconds since 1.1.1970 0:00:00 UTC, your output is obviously time depended.
The correct way to do what you want to do is using the C++11 <random> library. In your concrete example, this would look somewhat like this:
std::mt19937 rng (std::random_device{}());
std::uniform_int_distribution<> dist (0, 409);
auto random_number = dist(rng);
For more information on the evils of rand and the advantages of <random> have a look at this.
As a last remark, seeding std::mt19937 like I did above is not quite optimal because the MT's state space is much larger than the 32 bit you get out of a single call to std::random_device{}(). This is not a problem for toy programs and your standard school assignments, but for reference: Here is my take at seeding the MT's entire state space, plus some helpful suggestions in the answers.
From manual:
time() returns the time as the number of seconds since the Epoch,
1970-01-01 00:00:00 +0000 (UTC).
Which means that if you start your program twice both times at the same second you will initialize srand with same value and will get same state of PRNG.
And if you remove initialization via call to srand you will always get exactly same sequence of numbers from rand.
I'm afraid you can't get trully random numbers there. Built in functions are meant to provide just pseudo random numbers. Moreover using srand and rand, because the first uses the same approach as the second one. If you want to cook true random numbers, you must find a correct source of entrophy, working for example with atmospheric noise, as the approach of www.random.org.
The problem here consists in the seed used by the randomness algorithm: if it's a number provided by a machine, it can't be unpredictable. A normal solution for this is using external hardware.
Unfortunately you can't get a real random number from a computer without specific hardware (which is often too slow to be practical).
Therefore you need to make do with a pseudo generator. But you need to use them carefully.
The function rand is designed to return a number between 0 and RAND_MAX in a way that, broadly speaking, satisfies the statistical properties of a uniform distribution. At best you can expect the mean of the drawn numbers to be 0.5 * RAND_MAX and the variance to be RAND_MAX * RAND_MAX / 12.
Typically the implementation of rand is a linear congruential generator which basically means that the returned number is a function of the previous number. That can give surprisingly good results and allows you to seed the generator with a function srand.
But repeated use of srand ruins the statistical properties of the generator, which is what is happening to you: your use of srand is correlated with your system clock time. The behaviour you're observing is completely expected.
What you should do is to only make one call to srand and then draw a sequence of numbers using rand. You cannot easily do this in the way you've set things up. But there are alternatives; you could switch to a random number generator (say mersenne twister) which allows you to draw the (n)th term and you could pass the value of n as a command line argument.
As a final remark, I'd avoid using a modulus when drawing a number. This will create a statistical bias if your modulo is not a multiple of RAND_MAX.
Try by change the NULL in time(NULL) by time(0) (that will give you the current système time). If it doesn't work, you could try to convert time(0) into ms by doing time(0)*1000.
This question already has answers here:
can rand() be used to generate predictable data?
(4 answers)
Closed 8 years ago.
I am a bit confused by the implementation of the random number generator in C, which is also apparently different from that in C++
If I understand correctly, a call to 'srand(seed)' somehow initializes a hidden variable (the seed) that is accessible by 'rand()', which in turn points the function to a pre-generated sequence, like for example this one. Each successive call to 'rand()' advances the sequence (and apparently there are other ways to advance in C++), which also suggests the use of an internal hidden pointer or counter to keep track of the advance.
I have found many discussions on how the algorithms for pseudo-random number generation work and the documentation of the functions rand() and srand(), but haven't been able to find information about these hidden parameters and their behavior, except for the fact that according to this source, they are not thread-safe.
Could anybody here please shed some light as to how are these parameters defined and what should be their defined behavior according to the standards, or if their behavior is implementation-defined?
Are they expected to be local to the function/method that calls rand() and srand()? If so, is there a way to communicate them to another function/method?
If your answer is specific to either C or C++, please be so kind to point it out. Any information will be much appreciated. Please bear in mind that this question is not about the predictability of data generated by rand() and srand(), but about the requirements, status and functioning of their internal variables as well as their accessibility and scope.
The requirements on rand are:
Generates pseudo-random numbers.
Range is 0 to RAND_MAX (minimum of 32767).
The seed set by srand() determines the sequence of pseudo-random numbers returned.
It need not be thread-safe or even reentrant, the state can be stored in a static variable.
The standard does not define any way to recover the internal state for reseeding or anything else.
There is no requirement on what PRNG is implemented, so every implementation can have its own, though Linear Congrueantial Generators are a favorite.
A conforming (though arguably useless) implementation is presented in this dilbert strip:
http://dilbert.com/strips/comic/2001-10-25/
Or for those who like XKCD (It's a perfect drop-in for any C or C++ library ;-)):
For completeness, the standard quotes:
7.22.2.1 The rand function
The rand function computes a sequence of pseudo-random integers in the range 0 to
RAND_MAX.
The rand function is not required to avoid data races with other calls to pseudo-random
sequence generation functions. The implementation shall behave as if no library function
calls the rand function.
[...]
The value of the RAND_MAX macro shall be at least 32767.
7.22.2.2 The srand function
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.
The srand function is not required to avoid data races with other calls to pseudo-random
sequence generation functions. The implementation shall behave as if no library function
calls the srand function.
C++ includes rand, srand and RAND_MAX without change by reference from the C standard.
There are a few C++ library functions/classes which are explicitly documented to use the C random number generator though.
The following answer is for C; specifically, the 1999 standard.
The C99 standard is very light on actual implementation details for rand & srand. It simply states that the argument to srand is used "as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand."
In practice, the way it usually works is:
The C library defines an integer variable that rand and srand use to keep track of the PRNG's state.
srand sets the state variable to the supplied value.
rand takes the value of the state variable and performs some mathematical magic on it to produce two new integers: one is the pseudo-random number that it returns, and the other becomes the new value for the state variable, thus influencing the next call to rand (assuming srand isn't called before then).
The C standard gives an example of a possible implementation of rand and srand that exhibits this behavior:
static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void srand(unsigned int seed)
{
next = seed;
}