Sign in to follow this  
AngleWyrm

Seeding the new C++0x RNG

Recommended Posts

AngleWyrm    554
So I've activated support for the new features of C++0x for my compiler, and the following code compiles and runs:

#include <random>
#include <functional>
#include <iostream>
#include <iomanip>

int main(){
std::uniform_int_distribution<int> distribution(1, 6);
std::mt19937 rng;
auto generator = std::bind(distribution, rng);

// roll a set of six 3d6 stats, several times
for(int set=1; set<=10; set++){
for (int stat=1; stat<=6; stat++){
int rnd_3d6 =0;
for(int die=1; die<=3; die++){
rnd_3d6 += generator();
}
std::cout << std::setw(3) << rnd_3d6;
}
std::cout << std::endl;
}
}


Output:
12 13 12  7  8 18
13 17 10 12 5 11
17 13 10 13 13 13
10 6 11 10 3 16
8 14 8 6 11 6
9 12 16 12 10 10
7 15 13 8 12 15
14 13 6 8 13 10
9 9 11 14 12 10
14 13 13 13 12 10


But without a seeding function it produces the same set of numbers on every run. How do I seed this new beast? Also, I know that std::uniform_int_distribution isn't what I really want. Ideally I think it's a binomial_distribution over the range [3,18].

[Edited by - AngleWyrm on December 2, 2010 1:05:37 AM]

Share this post


Link to post
Share on other sites
nobodynews    3126
my19937 is a typedef, at least in Visual C++, for mersenne_twister class. Here is the documentation for that class. All that remains is you find a way to supply a new seed every time you create a new random number generator. I suggest something like the time function.

Share this post


Link to post
Share on other sites
AngleWyrm    554
Thanks; with that info, I've put the seeding function into the constructor and it works.

#include <random>
#include <functional>
#include <iostream>
#include <iomanip>

int main(){
std::uniform_int_distribution<int> distribution(1, 6);
std::mt19937 rng(time(NULL)); // seed rng during construction
auto generator = std::bind(distribution, rng);

// roll a set of six 3d6 stats, several times
for(int set=1; set<=10; set++){
for (int stat=1; stat<=6; stat++){
int rnd_3d6 =0;
for(int die=1; die<=3; die++){
rnd_3d6 += generator();
}
std::cout << std::setw(3) << rnd_3d6;
}
std::cout << std::endl;
}
}


Now all I gotta do is figure out the binomial_distribution thing. When I substitute binomial_distribution in place of uniform_int_distribution, it keeps generating 1*3=3's across the board, so either I'm not using it correctly or it doesn't work the way I think it does.

Share this post


Link to post
Share on other sites
Zahlman    1682
A binomial distribution gives you results that model a set of possibly-weighted coin flips - it's binomial because there are two outcomes for each thing that gets added together. You can't use this (at least, not with any real accuracy) to model six-sided dice. Just keep doing what you're doing with the loop.

Share this post


Link to post
Share on other sites
phresnel    953
Quote:
Original post by nobodynews
my19937 is a typedef, at least in Visual C++


It is also per The Next Holy Standard:

Quote:
N3126=10-01 16

26.5.2 Header <random> Synopsis


[...]
typedef see below mt19937;
typedef see below mt19937_64;
[...]


The standard even (partially) defines the output:

Quote:

26.5.5 Engines and adaptors with predefined parameters


[...]
typedef mersenne_twister_engine<uint_fast32_t, 32, 
624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15,
0xefc60000, 18, 1812433253>
mt19937;


Required behavior: The 10000th consecutive invocation of a default-constructed object of type mt19937 shall produce the value 4123659995.[...]


The latter thing being very important to me, as this is the first time I can portably rely on the standard library for generating content procedurally.

Share this post


Link to post
Share on other sites
AngleWyrm    554
Quote:
Original post by Zahlman
A binomial distribution gives you results that model a set of possibly-weighted coin flips - it's binomial because there are two outcomes for each thing that gets added together. You can't use this (at least, not with any real accuracy) to model six-sided dice. Just keep doing what you're doing with the loop.

Right you are, and I'll be keeping the for loop because it has a definite min and max of the dice. The distribution that 3d6 begins to represent is the Normal distribution, which can be specified with a mean and a standard deviation. I tried using a mean of 10.5 and a standard deviation of 2.5, and it seemed close to producing values from the distribution of 3d6.

#include <random>
#include <functional>
#include <iostream>
#include <iomanip>

int main(){
std::normal_distribution<double> distribution(10.5, 2.5);
std::mt19937 rng(time(NULL));

// roll a set of six 3d6 stats, several times
for(int set=1; set<=10; set++){
for (int stat=1; stat<=6; stat++){
std::cout << std::setw(3) << (int) distribution(rng);
}
std::cout << std::endl;
}
}


The only difference of course is that a normal distribution is unbounded, and merely has decreasing likelihood as the numbers spread away from average. It means it is possible (but highly unlikely) to roll a -1 or a 20. It isn't dice, but it's interesting.

[Edited by - AngleWyrm on December 2, 2010 5:50:33 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this