CS253: Software Development with C++

Spring 2018

Random Numbers

See this page as a slide show

CS253 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<5; i++)
        cout << gen() << '\n';
}
16807
282475249
1622650073
984943658
1144108930

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

Mersenne Twister

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

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

14514284786278117030
4620546740167642908
13109570281517897720
17462938647148434322
355488278567739596

True randomness

random_device gen;
for (int i=0; i<3; i++)
    cout << gen() << '\n';
399741577
2989652215
172325020

Cloudflare

The hosting service Cloudflare uses a unique source of randomness.

Seeding

minstd_rand a;
cout << a() << ' ' << a() << '\n';
minstd_rand b;
cout << b() << ' ' << b() << '\n';
minstd_rand c(123);
cout << c() << ' ' << c() << '\n';
182605794 48271
182605794 48271
985676192 5937333

Seeding

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

Seed with random_device

random_device gen;
auto seed = gen();
minstd_rand a(seed);
for (int i=0; i<5; i++)
    cout << a() << '\n';
1815786075
264574020
167270711
1933461608
485981148

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

Seed with time

// seconds since start of 1970
auto seed = time(nullptr);
minstd_rand a(seed);
for (int i=0; i<5; i++)
    cout << a() << '\n';
582071126
1626769445
900843393
215055400
3263802

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(seed);
for (int i=0; i<5; i++)
    cout << a() << '\n';
1873337173
1617270007
1914972153
1334695995
453480998

Better Seeding

Not good enough.

Distributions

  • Uniform:
    • uniform_int_distribution
    • uniform_real_distribution
  • Related to Bernoulli (yes/no) trials:
    • bernoulli_distribution
    • binomial_distribution
    • geometric_distribution
    • negative_binomial_distribution
  • Piecewise distributions:
    • discrete_distribution
    • piecewise_constant_distribution
    • piecewise_linear_distribution
  • Related to Normal distribution:
    • normal_distribution
    • lognormal_distribution
    • chi_squared_distribution
    • cauchy_distribution
    • fisher_f_distribution
    • student_t_distribution
  • Rate-based distributions:
    • poisson_distribution
    • exponential_distribution
    • gamma_distribution
    • weibull_distribution
    • extreme_value_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<10; x++)
        cout << fixed << setprecision(3) << dist(gen) << ' ';
    cout << '\n';
}
23.703 18.948 24.341 23.845 18.889 24.782 24.394 19.547 22.427 20.157 
18.683 21.831 19.949 19.319 21.828 24.950 24.703 24.975 24.754 24.774 
19.103 23.081 24.794 24.868 24.700 18.769 21.398 23.587 23.602 20.079 
18.993 18.033 20.952 18.787 24.410 22.478 23.545 24.149 24.716 21.526 
22.590 23.586 18.250 20.529 23.944 19.483 24.538 22.770 22.751 20.791 
23.304 23.185 23.202 21.323 20.746 20.955 22.588 19.217 19.198 20.113 
22.942 23.581 18.223 20.216 19.938 24.107 18.323 19.044 18.680 24.958 
23.764 23.753 22.864 18.876 20.220 23.346 24.652 21.434 18.241 22.645 
21.071 18.881 20.671 19.471 23.359 18.359 23.566 18.255 19.308 20.861 
21.428 21.206 21.119 21.413 22.524 23.558 22.966 24.446 23.283 23.653 

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<10; x++)
        cout << fixed << setprecision(3) << rng() << ' ';
    cout << '\n';
}
23.703 18.948 24.341 23.845 18.889 24.782 24.394 19.547 22.427 20.157 
18.683 21.831 19.949 19.319 21.828 24.950 24.703 24.975 24.754 24.774 
19.103 23.081 24.794 24.868 24.700 18.769 21.398 23.587 23.602 20.079 
18.993 18.033 20.952 18.787 24.410 22.478 23.545 24.149 24.716 21.526 
22.590 23.586 18.250 20.529 23.944 19.483 24.538 22.770 22.751 20.791 
23.304 23.185 23.202 21.323 20.746 20.955 22.588 19.217 19.198 20.113 
22.942 23.581 18.223 20.216 19.938 24.107 18.323 19.044 18.680 24.958 
23.764 23.753 22.864 18.876 20.220 23.346 24.652 21.434 18.241 22.645 
21.071 18.881 20.671 19.471 23.359 18.359 23.566 18.255 19.308 20.861 
21.428 21.206 21.119 21.413 22.524 23.558 22.966 24.446 23.283 23.653 

Binding with temporaries

auto rng = bind(uniform_real_distribution<float>(18.0, 25.0), mt19937());
for (int y=0; y<10; y++) {
    for (int x=0; x<10; x++)
        cout << fixed << setprecision(3) << rng() << ' ';
    cout << '\n';
}
23.703 18.948 24.341 23.845 18.889 24.782 24.394 19.547 22.427 20.157 
18.683 21.831 19.949 19.319 21.828 24.950 24.703 24.975 24.754 24.774 
19.103 23.081 24.794 24.868 24.700 18.769 21.398 23.587 23.602 20.079 
18.993 18.033 20.952 18.787 24.410 22.478 23.545 24.149 24.716 21.526 
22.590 23.586 18.250 20.529 23.944 19.483 24.538 22.770 22.751 20.791 
23.304 23.185 23.202 21.323 20.746 20.955 22.588 19.217 19.198 20.113 
22.942 23.581 18.223 20.216 19.938 24.107 18.323 19.044 18.680 24.958 
23.764 23.753 22.864 18.876 20.220 23.346 24.652 21.434 18.241 22.645 
21.071 18.881 20.671 19.471 23.359 18.359 23.566 18.255 19.308 20.861 
21.428 21.206 21.119 21.413 22.524 23.558 22.966 24.446 23.283 23.653 

Boolean Values

constexpr int nrolls=10000;

auto rng = bind(bernoulli_distribution(0.42), knuth_b());

int count=0;
for (int i=0; i<nrolls; i++)
    if (rng())
        count++;
cout << "true: " << count*100.0/nrolls << "%\n";
true: 41.93%

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: 

Passwords

mt19937 gen;
uniform_int_distribution<char> dist('a','z');
for (int y=0; y<8; y++) {
    string pw;
    for (int x=0; x<12; x++)
        pw += dist(gen);
    cout << "Password: " << pw << '\n';
}
Password: vdxvdzxfqico
Password: heozyzzzeszz
Password: ycmuuhdakcxq
Password: uwynruajwfyr
Password: rktttmkkreeh
Password: suaihwbdczvv
Password: sditymarldjf
Password: tbuaekmllmqu

Passwords

With binding:

mt19937 gen;
uniform_int_distribution<char> dist('a','z');
auto rng = bind(dist, gen);
for (int y=0; y<8; y++) {
    string pw;
    for (int x=0; x<12; x++)
        pw += rng();
    cout << "Password: " << pw << '\n';
}
Password: vdxvdzxfqico
Password: heozyzzzeszz
Password: ycmuuhdakcxq
Password: uwynruajwfyr
Password: rktttmkkreeh
Password: suaihwbdczvv
Password: sditymarldjf
Password: tbuaekmllmqu

Passwords

With extreme binding:

auto rng = bind(uniform_int_distribution<char>('a','z'), mt19937());
for (int y=0; y<8; y++) {
    string pw;
    for (int x=0; x<12; x++)
        pw += rng();
    cout << "Password: " << pw << '\n';
}
Password: vdxvdzxfqico
Password: heozyzzzeszz
Password: ycmuuhdakcxq
Password: uwynruajwfyr
Password: rktttmkkreeh
Password: suaihwbdczvv
Password: sditymarldjf
Password: tbuaekmllmqu

User: Guest

Check: HTML CSS
Edit History Source

Modified: 2018-05-02T14:22

Apply to CSU | Contact CSU | Disclaimer | Equal Opportunity
Colorado State University, Fort Collins, CO 80523 USA
© 2018 Colorado State University
CS Building