CS253

CS253: Software Development with C++

Spring 2017

Random Numbers

See this page as a slide show

Random Numbers

Philosophy

“Computers can’t do anything truly random. Only a person can do that.”

Traditional Method

Traditionally, random number generators work like this:

unsigned n = 1;
for (int i=0; i<5; i++) {
    n = n * 16807 % 2147483647;
    cout << n << '\n';
}
16807
282475249
1622647863
947787490
1578127215

Overview

Generators

EngineDescription
default_random_engineDefault random engine
minstd_randMinimal Standard minstd_rand generator
minstd_rand0Minimal Standard minstd_rand0 generator
mt19937Mersenne Twister 19937 generator
mt19937_64Mersenne Twister 19937 generator (64 bit)
ranlux24_baseRanlux 24 base generator
ranlux48_baseRanlux 48 base generator
ranlux24Ranlux 24 generator
ranlux48Ranlux 48 generator
knuth_bKnuth-B generator
random_deviceTrue random number generator

Default Engine

Define a random-number generator, and use () to generate a number. This is not a function call, because gen is an object, not a function. It’s operator().

#include <random>
#include <iostream>

using namespace std;

int main() {
    default_random_engine gen;
    for (int i=0; i<3; i++)
        cout << gen() << '\n';
}
16807
282475249
1622650073

I won’t bother with the #includes in subsequent examples.

Mersenne Twister

mt19937_64 gen;
cout << "min=" << gen.min() << '\n'
     << "max=" << gen.max() << "\n\n";
for (int i=0; i<3; i++)
    cout << gen() << '\n';
min=0
max=18446744073709551615

14514284786278117030
4620546740167642908
13109570281517897720

Here’s a different, 64-bit generator. You can use .min() and .max() to find out the range of a given generator.

True randomness

random_device gen;
for (int i=0; i<3; i++)
    cout << gen() << '\n';
3019983365
2930815873
357321206

Seeding

minstd_rand gen, a(1), b(123), c(8675309);
cout << gen() << '\n';
cout << a() << '\n';
cout << b() << '\n';
cout << c() << '\n';
48271
48271
5937333
6529574

Seed with random_device

random_device gen;
const auto seed = gen();
minstd_rand a, b(seed);
for (int i=0; i<3; i++)
    cout << a() << '\n';
for (int i=0; i<3; i++)
    cout << b() << '\n';
48271
182605794
1291394886
1567044268
1977362347
52193828

You can seed with random_device, if you know that it’s truly random.

Seed with time

// seconds since start of 1970
const auto seed = time(nullptr);
minstd_rand a, b(seed);
for (int i=0; i<3; i++)
    cout << a() << '\n';
for (int i=0; i<3; i++)
    cout << b() << '\n';
48271
182605794
1291394886
687609350
83685818
181380671

Seed with more accurate time

C++ provides a more accurate time—nanoseconds make more possibilities:

auto seed = chrono::high_resolution_clock::now()
            .time_since_epoch().count();
minstd_rand a, b(seed);
for (int i=0; i<3; i++)
    cout << a() << '\n';
for (int i=0; i<3; i++)
    cout << b() << '\n';
48271
182605794
1291394886
1856081930
1913090190
684773196

Better Seeding

Distribution

Distributions

  • Uniform:
    • uniform_int_distribution
    • uniform_real_distribution
  • Related to Bernoulli (yes/no) trials:
    • bernoulli_distribution
    • binomial_distribution
    • geometric_distribution
    • negative_binomial_distribution
  • Rate-based distributions:
    • poisson_distribution
    • exponential_distribution
    • gamma_distribution
    • weibull_distribution
    • extreme_value_distribution
  • Related to Normal distribution:
    • normal_distribution
    • lognormal_distribution
    • chi_squared_distribution
    • cauchy_distribution
    • fisher_f_distribution
    • student_t_distribution
  • Piecewise distributions:
    • discrete_distribution
    • piecewise_constant_distribution
    • piecewise_linear_distribution

uniform_int_distribution

mt19937 gen;
uniform_int_distribution<int> dist(1,6);
for (int y=0; y<10; y++) {
    for (int x=0; x<40; x++)
        cout << dist(gen) << ' ';
    cout << '\n';
}
5 1 6 6 1 6 6 2 4 2 1 4 2 2 4 6 6 6 6 6 1 5 6 6 6 1 3 5 5 2 1 1 3 1 6 4 5 6 6 4 
4 5 1 3 6 2 6 5 5 3 5 5 5 3 3 3 4 2 2 2 5 5 1 2 2 6 1 1 1 6 5 5 5 1 2 5 6 3 1 4 
3 1 3 2 5 1 5 1 2 3 3 3 3 3 4 5 5 6 5 5 2 5 5 1 4 5 1 4 1 3 3 5 6 4 3 6 4 5 2 1 
5 5 2 5 4 6 5 3 6 3 6 4 4 1 1 5 1 2 2 5 6 6 2 2 5 2 2 1 6 2 3 6 2 6 2 6 4 5 3 6 
3 1 5 5 4 4 4 5 6 5 2 5 5 3 5 4 3 2 4 4 1 3 1 3 4 4 5 3 6 6 1 1 4 3 3 3 1 5 3 3 
1 6 5 3 2 6 4 4 1 1 4 3 2 3 4 4 5 5 5 6 3 5 1 6 2 4 6 4 1 4 5 3 4 4 6 3 1 6 3 4 
1 3 6 6 1 1 5 6 5 3 6 5 1 3 3 6 2 1 5 4 3 5 6 1 2 6 2 1 1 2 1 5 6 1 4 4 4 1 1 5 
6 4 4 3 3 2 4 1 3 3 1 5 2 1 1 2 2 4 2 5 3 6 1 5 6 2 6 1 3 2 3 4 3 6 6 3 3 1 1 1 
5 6 3 2 2 2 3 3 1 2 1 3 6 6 6 4 4 5 1 3 2 4 3 1 5 2 1 3 1 6 2 5 4 2 5 1 4 3 3 3 
4 5 2 2 5 4 2 5 5 2 2 3 3 3 4 5 5 5 1 3 6 3 5 2 3 6 3 3 3 5 2 1 4 3 4 6 5 3 5 6 

uniform_real_distribution

mt19937 gen;
uniform_real_distribution<float> dist(18.0, 25.0);
for (int y=0; y<10; y++) {
    for (int x=0; x<12; x++)
        cout << fixed << setprecision(2) << dist(gen) << ' ';
    cout << '\n';
}
23.70 18.95 24.34 23.85 18.89 24.78 24.39 19.55 22.43 20.16 18.68 21.83 
19.95 19.32 21.83 24.95 24.70 24.98 24.75 24.77 19.10 23.08 24.79 24.87 
24.70 18.77 21.40 23.59 23.60 20.08 18.99 18.03 20.95 18.79 24.41 22.48 
23.55 24.15 24.72 21.53 22.59 23.59 18.25 20.53 23.94 19.48 24.54 22.77 
22.75 20.79 23.30 23.18 23.20 21.32 20.75 20.95 22.59 19.22 19.20 20.11 
22.94 23.58 18.22 20.22 19.94 24.11 18.32 19.04 18.68 24.96 23.76 23.75 
22.86 18.88 20.22 23.35 24.65 21.43 18.24 22.65 21.07 18.88 20.67 19.47 
23.36 18.36 23.57 18.26 19.31 20.86 21.43 21.21 21.12 21.41 22.52 23.56 
22.97 24.45 23.28 23.65 19.93 22.94 22.76 18.02 22.59 22.97 19.14 22.51 
18.83 21.19 21.49 23.42 24.72 22.02 20.38 24.14 22.10 23.66 19.57 18.12 

Binding

mt19937 gen;
uniform_real_distribution<float> dist(18.0, 25.0);
auto rng = bind(dist, gen);
for (int y=0; y<10; y++) {
    for (int x=0; x<12; x++)
        cout << fixed << setprecision(2) << rng() << ' ';
    cout << '\n';
}
23.70 18.95 24.34 23.85 18.89 24.78 24.39 19.55 22.43 20.16 18.68 21.83 
19.95 19.32 21.83 24.95 24.70 24.98 24.75 24.77 19.10 23.08 24.79 24.87 
24.70 18.77 21.40 23.59 23.60 20.08 18.99 18.03 20.95 18.79 24.41 22.48 
23.55 24.15 24.72 21.53 22.59 23.59 18.25 20.53 23.94 19.48 24.54 22.77 
22.75 20.79 23.30 23.18 23.20 21.32 20.75 20.95 22.59 19.22 19.20 20.11 
22.94 23.58 18.22 20.22 19.94 24.11 18.32 19.04 18.68 24.96 23.76 23.75 
22.86 18.88 20.22 23.35 24.65 21.43 18.24 22.65 21.07 18.88 20.67 19.47 
23.36 18.36 23.57 18.26 19.31 20.86 21.43 21.21 21.12 21.41 22.52 23.56 
22.97 24.45 23.28 23.65 19.93 22.94 22.76 18.02 22.59 22.97 19.14 22.51 
18.83 21.19 21.49 23.42 24.72 22.02 20.38 24.14 22.10 23.66 19.57 18.12 

Histogram

mt19937 gen;
normal_distribution<double> dist(21.5, 1.5);
auto rng = bind(dist, gen);
map<int,int> tally;
for (int i=0; i<10000; i++)
    tally[rng()]++;
for (auto p : tally)
    cout << p.first << ": " << string(p.second/100,'#') << '\n';
15: 
16: 
17: #
18: ###
19: ###########
20: #####################
21: #########################
22: ####################
23: ###########
24: ###
25: 
26: 

Modified: 2017-05-03T11:04

User: Guest

Check: HTML CSS
Edit History Source
Apply to CSU | Contact CSU | Disclaimer | Equal Opportunity
Colorado State University, Fort Collins, CO 80523 USA
© 2015 Colorado State University
CS Building