rand

Probably the simplest way of generating a pseudo-random sequence is using the couple of functions srand() and rand(), part of the C standard library.

Their usage is quite strightforward. We use srand() to select a specific sequence, and then we call rand() any time we want the next value in our pseudo-random sequence.

We immediately see that the weakest link in this way of proceeding is the startup. If we always feed srand() with the same seed, we always ends up with the same sequence, and that is not usually the expected behaviour.

But for this problem there is a easy solution: we use as a seed the current time. Usually this is enough to guarantee a certain variety in the results.

There is another caveat, though. If you are using VC++, the first number generated by rand() tends to change only slightly as answer to the usage of increasing seed for srand() . Looks like this is a sort of bug, but I didn't investigate much on the matter, since there is a really immediate workaround: discard the first generated value, and start using the second. Well, it is not expecially elegant, but it is cheap and it works fine.

As we can see in the output of the example (when we run it, otherwise trust me), the generated numbers tend to be equally distributed, and that is often what we are expecting by a pseudo-random sequence.

#include <cstdlib>
#include <iostream>
#include <ctime>
#include <vector>
#include <algorithm>

using namespace std;

namespace
{
void dump(vector<int>& v)
{
auto f = [] (int x) { static int i = 0; cout << '[' << ++i << " = " << x << "] "; };
for_each(v.begin(), v.end(), f);
cout << endl;
}
}

int main()
{
vector<int> vec(64, 0);

srand(static_cast<unsigned int>(time(0))); // 1.
rand(); // discard the first value generated

for(int i = 0; i < 6400000; ++i)
{
int value = static_cast<int>((static_cast<double>(rand())/(RAND_MAX + 1)) * 64); // 2.
++vec[value];
}

dump(vec);
system("pause");
}

1. time() returns a time_t value, srand() wants an unsigned int as parameter, with an explicit cast we get rid of a warning about a possible precision loss.
2. As you can see, I was interested in getting pseudo-random numbers in the interval [0..63], so I casted the integer generated by rand() in a double in the interval [0..1), multiplied the result by 64 and casted back to an integer. A lot of casting, but (mostly) harmless.

No comments:

Post a Comment