C++ Random Numbers with mt19937 and uniform_int_distribution
Do not use rand(). It is old, of low quality and has a bad range. Modern C++ uses a generator (an engine) and a distribution from <random>.
A dice and a decimal number
#include <iostream>
#include <random>
int main() {
std::random_device device; // a true random seed, if the system has it
std::mt19937 gen(device()); // the engine (Mersenne Twister)
std::uniform_int_distribution<int> dice(1, 6);
std::uniform_real_distribution<double> unit(0.0, 1.0);
bool all_ok = true;
for (int i = 0; i < 1000; i++) {
int d = dice(gen);
double u = unit(gen);
all_ok = all_ok && d >= 1 && d <= 6 && u >= 0.0 && u < 1.0;
}
std::cout << "1000 numbers, all in range: " << all_ok << '\n';
}
Output
1000 numbers, all in range: 1
Every run gives different numbers, so we only check the range. When you run it, print dice(gen) to see them.
A fixed seed: the same numbers every time
For tests and games with a “seed”, give the engine a number. The mt19937 engine is exactly defined by the standard, so its raw numbers are the same everywhere:
#include <iostream>
#include <random>
int main() {
std::mt19937 a(42);
std::cout << a() << ' ' << a() << ' ' << a() << '\n';
std::mt19937 c(42), d(42); // two engines with the same seed
std::cout << std::boolalpha << (c() == d()) << ' ' << (c() == d()) << '\n';
}
Output
1608637542 3421126067 4083286876
true true
The distributions (like uniform_int_distribution) can give different numbers on different compilers, even with the same seed. Only the engine is fully fixed.
Shuffle and pick
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>
int main() {
std::vector<int> cards = {1, 2, 3, 4, 5, 6, 7, 8};
std::mt19937 gen(std::random_device{}());
std::shuffle(cards.begin(), cards.end(), gen);
std::cout << cards.size() << " cards, sorted again: ";
std::sort(cards.begin(), cards.end());
for (int c : cards) std::cout << c << ' ';
std::cout << '\n';
std::uniform_int_distribution<std::size_t> pick(0, cards.size() - 1);
std::cout << "random index in range: " << (pick(gen) < cards.size()) << '\n';
}
Output
8 cards, sorted again: 1 2 3 4 5 6 7 8
random index in range: 1
Good to know
- Create the engine once and reuse it. Do not make a new one for every number.
mt19937is not safe for passwords or keys. For security use the random functions of the operating system or a crypto library.std::random_devicecan be weak on some old systems.
Related: C++ Algorithms and C++ Vectors.
Learn more about the similar topics:
| Tutorials |
|---|
| No Content Found. |
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |