2

I'm sorry if this is kind of a dumb question, but I'm new to c++, and honestly can't find the answer;

When I use rand(), of course I have to first use srand().

At first i'd just import <ctime> and do srand(time()), and this worked. But if I called rand() more than once a second - how often time() changes - then I'd get the same answer. So for instance;

#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

int main()
{
    bool x = true;
    while(x == true)
    {
        int num = 1;
        srand(time(NULL));
        num = rand();
        cout<<num%10<<endl;
    }

}

Might produce something like, 6666666666777777777700000000003333333333

Which is no good for my purposes - I'd prefer something like 163509284749301935766.

Charles Noon
  • 559
  • 3
  • 10
  • 16

2 Answers2

8

You should only seed the random number generator once. Right now you are seeding it in the loop and using time(NULL) just means the seed changes once per second which gives you the bad output you have described.

DO this instead:

int main()
{
    bool x = true;
    int num = 1;
    srand(time(NULL));
    while(x == true)
    {
        num = rand();
        cout<<num%10<<endl;
    }
}

And if you really care about the random numbers generated you might want to use something other than rand(). The reason is that rand() has poor statistical properties for pseudo random number generation, it is often implemented as a Linear congruential generator. If you need high quality randomness then you should prefer something else such as the new c++ random number generators http://en.cppreference.com/w/cpp/numeric/random. In fact there's even a report on depreciating the old rand() to try to push people to use the newer c++ standard library random functions.

In this particular case you take a modulus which causes a few subtle problems:

num = rand();
cout<<num%10<<endl;

Even if rand() was perfect if the modulus here isn't a divisor of the maximum value returned by rand() you will get a non-uniform distribution as a result. Here's a quick explanation, say rand() returned values in the range of [0,25] then taking the modulus would do the following.

before    after modulus 
[0-9]         [0-9]
[10-19]       [0-9]
[20-25]       [0-5]

You'll see that you are more likely to get [0-5] than [6-9] which means you now no longer have a uniform number being generated. Note that this small range is for educational purposes only, the maximum value of rand() is mandated by the standard to be at least 32767. However it illustrates an important point, the larger the maximum generated number the better.

This uniformity of distribution problem aside the modulus has the particularly insidious effect of decreasing the quality of the pseudo-randomness even further for some implementations.

Using std::uniform_int_distribution avoids many problems so I would recommend changing your existing code to use the new library. Doing so would look like this:

#include <iostream>
#include <random>
using namespace std;

int main()
{
    std::default_random_engine generator;
    generator.seed( /* your seed for the RNG goes here */ );
    std::uniform_int_distribution<int> distribution(0,9);//note the min and max parameters are inclusive here
    while(true)
    {
        cout << distribution(generator) << endl;
    }

}
shuttle87
  • 15,466
  • 11
  • 77
  • 106
4

A function f() that would generate random numbers in range [low,high] can be easily, robustly and safely defined with c++11 library facilities :

#include <random>
#include <iostream>

int f(int low, int high)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(low, high);

    return dis(gen);
}

std::uniform_int_distribution will give you a random number in your range (eg (0,9) ) this way

On the rationale behind refraining from using the old rand you can check this

Community
  • 1
  • 1
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153