random in class member function

Pages: 12
Hello what is the best place for srand(time(0)); in the main function ? at the beginning of the program ? or in the function itself as below ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <algorithm>
#include <bits/stdc++.h>
#include <stdlib.h>
#include <sstream>
#include <ctime>
#include <vector>
using namespace std;

class Box
{
	public:

	int from;
	int to;

	double getRandom(void);
	void setminus(int min);
	void setmaximus(int max);

};

double Box::getRandom(void)
{
        //is this the right place ?
	srand(time(0));
	return rand() % (to - from + 1) + from;
}

void Box::setminus(int min)
{
	from = min;
}

void Box::setmaximus(int max)
{
	to = max;
}

int main()
{
	Box Box1;
	Box1.setminus(20);
	Box1.setmaximus(50);

	int rand_num = Box1.getRandom();

	cout << "Random number : " << rand_num << endl;
}
Last edited on
You only want to seed the random number generator 1 time, so put it in main().

If you leave it where it is, if you have a loop that calls getRandom multiple times within the same second, the RNG will be seeded with the same seed each time, and you will get the same result from rand() each time.
if you want to bother you can use static variables to control it, but start of main is the usual best spot esp for small programs. Also consider <random>.
Hello, ok thank you, as it is to make several simulation as quickly as possible it is thus preferable that I place srand(time(0)); in the main function. For the random you were talking about code like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<random>
#include<chrono>
using namespace std;
 
//======== Random dice roll ==========

mt19937                       diceGenerator   ( chrono::system_clock::now().time_since_epoch().count() );
uniform_int_distribution<int> diceDistribution( 1, 6 );

int diceRoll()
{
   return diceDistribution( diceGenerator );
}

//====================================


int main()
{
   int counts[1+6] = { 0 };
   int nmax;

   cout << "How many rolls? ";    
   cin >> nmax;

   for ( int i = 1; i <= nmax; i++ ) counts[ diceRoll() ]++;

   for ( int j = 1; j <= 6   ; j++ ) cout << j << ": " << 100.0 * counts[j] / nmax << "%\n";
}


Posted in the forum by lastchance :
http://www.cplusplus.com/forum/beginner/208037/


Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string>
#include <algorithm>
#include <bits/stdc++.h>
#include <stdlib.h>
#include <sstream>
#include <ctime>
#include <vector>
#include <random>
#include <chrono>
using namespace std;

class Box
{
	public:

		int from;
	int to;

	double getRandom(void);
	void setminus(int min);
	void setmaximus(int max);

};

double Box::getRandom(void)
{
	mt19937 diceGenerator(chrono::system_clock::now().time_since_epoch().count());
	uniform_int_distribution<int> diceDistribution(from, to);
	return diceDistribution(diceGenerator);
}

void Box::setminus(int min)
{
	from = min;
}

void Box::setmaximus(int max)
{
	to = max;
}

int main()
{
	Box Box1;
	Box1.setminus(20);
	Box1.setmaximus(50);

	int rand_num = Box1.getRandom();

	cout << "Random number : " << rand_num << endl;
}
Last edited on
In line 28, you are creating a new mt19937 each time the function is called. You are passing it the time as a seed.

While the time being passed in has finer granularity than seconds, there is no need to reseed the RNG each time you use it.

Instead, make diceGenerator a member of Box, and seed it during Box's constructor.

As far as the use of these more advanced RNGs... I understand that they are better than rand(), but I have not actually used random number generation in my work for a long time. Thus, I am not able to weigh in on whether you are using the distribution and generator correctly.


Slightly off topic: Not to start an argument, but for toy problems and simple simulations, is there a strong reason to avoid rand()? Understanding that the generated values may be less random and come with fewer features than other PRNGs, wouldn't rand() be good enough for examples and maybe classroom assignments?

I do understand not wanting to ingrain outdated language structures (char* vs. std::string), but with PRNGs, there is the issue of which one to use, understanding what distribution is required, understanding how the algorithm works in order to make wise choices, etc. For simple example programs where you simply want a random number to trigger some alternate behavior, wouldn't rand() be an adequate but simpler choice?
yes, for a toy, rand is fine.
but no, it isnt much simplier. you are talking saving 1-2 lines of code to use rand instead of an *identical to rand* wrapper around <random>. And the 1-2 lines pales beside having to % everything all the time, instead of having the stream capped to your range. Trying to do from 32 to 127 with rand (printable char generator?) is a hassle compared to <random>.

on my box rand is a little faster, but they are both sluggish if you are in a big hurry.
Last edited on
If it's about security, I found this piece of code on stackoverflow.com.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdint> //`uint32_t`
#include <functional> //`std::hash`
#include <random> //`std::mt19937`
#include <iostream> //`std::cout`
#include <chrono> 

static std::mt19937 rng;

static void seed(uint32_t seed) {
    rng.seed(static_cast<std::mt19937::result_type>(seed));
}
static void seed() {
    uint32_t t = static_cast<uint32_t>( time(nullptr) );
    std::hash<uint32_t> hasher; size_t hashed=hasher(t);
    seed( static_cast<uint32_t>(hashed) );
}

int main(int /*argc*/, char* /*argv*/[]) {
    seed();
    std::uniform_int_distribution<> dis(0, 5);
    std::cout << dis(rng);
}
Last edited on
@jonnin

Thanks for the input. I guess because I understood rand(), the overhead to learn how the other PRNGs worked was never worth it for the rare times I have needed it.

I think next time I want rand(), I'll go ahead and learn how the others work.

Doug
Hi, thanks for the documentation, that's great.
The proposed toolkit in that working paper hides a lot of the drudgery out of using the C++ <random> & <chrono> libraries when generating random numbers. Almost as simple as C's random generation with rand/srand, yet more robust and feature rich than what C offers.

When writing C++ code you should seriously consider never using the C library. Even the C standard recommends not using rand/srand if there are alternatives available. With C++ there are almost too many.

https://web.archive.org/web/20180123103235/http://cpp.indi.frih.net/blog/2014/12/the-bell-has-tolled-for-rand/

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

I've shamelessly mashed together my own version of that toolkit as a header-only file, with a couple of modifications and added functions. Wrapped in a custom namespace. When I need some quick random number generation, such as a die roll, I include the header. I seed the engine and then call one of the custom functions. I have written the header that trying to seed the engine multiple times won't happen unless I deliberately indicate I want a new seed.
Hello, this is a good idea can you tell me what is the safest way to generate random numbers in a C++11 program?
@Furry Guy,

Thanks for the links. I have only had time to read the web.archive.org article, but it gave me a good perspective.

I think this quote from the article describes my situation pretty well (as long as you replace the work "newcomer" with the phrase "programmer comfortable in his ways"):

A newcomer that just wants to roll a programmatic die first has to choose an engine – and the choice is hardly obvious. Then they have to decide whether they want to apply one of the adaptors. Then they have to decide how to seed it. And then, after all that, they have to search through the distributions to decide which is the right match. When you know the default choices (mt19937 seeded via random_device, used with either uniform_int_distribution or uniform_real_distribution), it’s natural and easy, but when you don’t, it’s overwhelming. As bad as it is, it’s not hard to understand why a newbie might want to just write rand() % 6 + 1 and be done with it.


I promise to move forward next time I need to work with random numbers.

Doug
I am right there with you Doug. Its been tough to relearn -- I think a newcomer with good info would be better off! I am coming in from 'long ago' until 'visual 2008' and then dropping the language for a while, I come back and its been like a new language, or maybe more like learning a giant new library that replaces everything I used to DIY. Ive slowly gotten better, but it still feels like everything I learn leads to 2 more things.

@oneidacharisse,

I'm sorry to have hijacked your thread a bit. The information that @Furry Guy has provided is terrific. However, your latest question may have become hidden.

In order to make it up to you, I am bumping your question here:

Hello, this is a good idea can you tell me what is the safest way to generate random numbers in a C++11 program?


Hopefully, somebody will respond to your question on your thread.

Have a good day.
What is the safest way to generate random numbers? I use my toolkit header. ;)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include "random_toolkit.hpp"

int main()
{
   rtk::srand();

   for (size_t i { }; i < 10; i++)
   {
      std::cout << rtk::rand(1, 10) << ' ';
   }
   std::cout << '\n';
}

One thing to note about the working paper's simple toolkit. It uses std::default_random_engine. Not std::mt19937. So if I'm going to not use my toolkit std::default_random_engine is the engine I will usually use. Implementation defined, and generally the simplest behind-the-scenes calculation for obtaining a random number.

On Windows MinGW's implementation of std::random_device is "broken." It does not provide a true random number series at all. As far as this hobbyist programmer can tell that engine is deterministic, so with MinGW it produces pseudo-random numbers. The same as the other engines. With MSVC it is non-deterministic and works as advertised.

it’s not hard to understand why a newbie might want to just write rand() % 6 + 1 and be done with it.

That is what the 2013 working paper I linked earlier tries to address. Ease of use. The reason I mashed up my own version into a header-only file.

Well, creating it was also a helpful learning experience too. Now creating random numbers in C++ is about as easy as using the C library. No, it isn't strictly cross-platform builtin C++ standard, but IMO it's close. AFAIK the header file doesn't depend on any one compiler to work.
On Windows MinGW's implementation of std::random_device is "broken."

Is that still the case?
It's obviously a simple bug to fix.
Ok, to truly answer your question of IMO, just IMO, what is the safest way to generate random numbers:

1. Include <random> and <chrono>.

2. Create an instance of std::default_random_engine:
std::default_random_engine URNG;

3. Create a seed sequence using std::random_device and the system clock:
1
2
3
4
std::seed_seq::result_type seeds[] { std::random_device {}(),
                                     std::seed_seq::result_type(std::chrono::system_clock::now().time_since_epoch().count()) };

std::seed_seq sseq(std::begin(seeds), std::end(seeds));

4. Seed the engine:
URNG.seed(sseq);

You can seed the engine on creation, as long as you create the seed sequence first:
std::default_random_engine URNG(sseq);

Why use a seed sequence using std::random_device and the system clock? To add a bit of randomness to the seed with each run, IF std::random_device works. If it doesn't then seeding with the system clock works for most “casual, inexpert, and/or lightweight uses.”

5. Create a distribution that lets you create uniform integer or floating point (double) numbers:
1
2
std::uniform_int_distribution<int>     idist(from, to);
std::uniform_real_distribution<double> ddist(from, to);

For example, you want to roll a 6-sided die:
std::uniform_int_distribution<int> die(1, 6);

6. Obtain a random number using the distribution and the random engine:
int pip { die(URNG) };

You now have a random integer number between 1 & 6, inclusive.

Now, definitely this is not as easy to use as rand/srand. Hide all these steps in a header-only file and that changes.

In my header file I added some basic error checking for the distributions where if the programmer enters wrong parameters, the first is higher than the second for example, it throws an error. And added some checks that prevent seeding the engine more than once won't happen, unless you force the seeding.
@dutch, as of the MinGW that is bundled with the latest Windows version of Code::Blocks std::random_device is still "broken."

Yes, it SHOULD be an easy fix, but so far no one has done it. If MSVC can make the engine work, MinGW should as well.
Pages: 12