Skip to content

Random

Random

The random number library provides classes that generate random and pseudo-random numbers. These classes include:

  • Uniform random bit generators (URBGs), which include both random number engines, which are pseudo-random number generators that generate integer sequences with a uniform distribution, and true random number generators if available;
  • Random number distributions (e.g. uniform, normal, or poisson distributions) which convert the output of URBGs into various statistical distributions

URBGs and distributions are designed to be used together to produce random values. All of the random number engines may be specifically seeded, serialized, and deserialized for use with repeatable simulators.

1
#include <random>

1
2
// Usually a high-cost generator
std::random_device rd;

1
unsigned int seed = rd();

1
2
3
// We recur to a user-defined function to mix other sources
// of entropy in the seed
seed = mix_seed(seed);

1
2
// This is the generator we will ultimately use
std::default_random_engine g(seed);

1
std::uniform_real_distribution<double> distribution(1.0, 10.0);

1
std::cout << distribution(g) << '\n';

1
std::mt19937 g2{seed};

1
std::normal_distribution<double> d2(0.0, 1.0);

1
std::cout << d2(g2) << '\n';

1
2
3
4
5
6
7
std::vector<int> hist(10, 0);
for (int i = 0; i < 300; ++i) {
    auto bin = d2(g2) + static_cast<double>(hist.size()) / 2;
    if (bin >= 0. && static_cast<size_t>(bin) < hist.size()) {
        ++hist[static_cast<size_t>(bin)];
    }
}

1
2
3
4
5
6
7
for (int n : hist) {
    std::cout << '-';
    for (int j = 0; j < n; ++j) {
        std::cout << '*';
    }
    std::cout << '\n';
}

 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
constexpr uint32_t fnv(uint32_t hash, const char *pos) {
    return *pos == '\0' ? hash : fnv((hash * 16777619U) ^ *pos, pos + 1);
}

unsigned int mix_seed(unsigned int seed) {
    // Mix seed with some cross-platform entropy sources
    // - Mix the current time
    seed ^= static_cast<unsigned int>(
        std::chrono::system_clock::now().time_since_epoch().count());

    // - Mix an arbitrary compile-time stamp
    constexpr uint32_t compile_stamp =
        fnv(2166136261U, __DATE__ __TIME__ __FILE__);
    seed ^= static_cast<unsigned int>(compile_stamp);

    // - Mix an arbitrary heap address
    auto heap_addr = std::make_unique<int>(0);
    seed ^=
        static_cast<unsigned int>(reinterpret_cast<uintptr_t>(heap_addr.get()));

    // - Mix an arbitrary stack address
    seed ^= static_cast<unsigned int>(reinterpret_cast<uintptr_t>(&heap_addr));

    // - Mix an arbitrary fixed number / counter
    seed ^= static_cast<unsigned int>(45);

    // - Mix an arbitrary function address (the clock function `now`)
    seed ^= static_cast<unsigned int>(
        reinterpret_cast<uintptr_t>(&std::chrono::system_clock::now));

    // - Mix the exit function address
    seed ^=
        static_cast<unsigned int>(reinterpret_cast<uintptr_t>((void *)&_Exit));

    // - Mix the random_device generator type hash code
    seed ^= static_cast<unsigned int>(typeid(std::random_device).hash_code());

    return seed;
}

Share Snippets