Seeding the new C++0x RNG

Started by
4 comments, last by AngleWyrm 13 years, 4 months ago
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 1813 17 10 12  5 1117 13 10 13 13 1310  6 11 10  3 16 8 14  8  6 11  6 9 12 16 12 10 10 7 15 13  8 12 1514 13  6  8 13 10 9  9 11 14 12 1014 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]
--"I'm not at home right now, but" = lights on, but no ones home
Advertisement
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.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

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.
--"I'm not at home right now, but" = lights on, but no ones home
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.
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.
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]
--"I'm not at home right now, but" = lights on, but no ones home

This topic is closed to new replies.

Advertisement