std::mt19937 în C++

Generatorul Mersenne Twister: numere pseudo-aleatorii rapide și de calitate, reproductibile cu un seed fix.

Sintaxă
std::mt19937 gen;             // seed implicit 5489
std::mt19937 gen(seed);
std::uint_fast32_t x = gen();

Ce face std::mt19937

std::mt19937 este generatorul recomandat pentru jocuri, simulări și teste. Fiecare apel gen() dă un număr pe 32 de biți. Secvența este complet determinată de seed: același seed dă exact aceleași numere, pe orice compilator, pentru că algoritmul este fixat de standard.

Numerele brute se folosesc rar direct. De obicei treci generatorul unei distribuții (std::uniform_int_distribution, std::normal_distribution), care le transformă în intervalul dorit; rezultatul distribuțiilor poate diferi între biblioteci. Pentru numere pe 64 de biți există std::mt19937_64.

Parametri

Parametru Descriere
seed Opțional. Valoarea de pornire; implicit 5489.

Ce returnează

Fiecare apel gen() returnează următorul număr din secvență (între 0 și 4294967295).

Exemple

Exemplul 1: Același seed, aceleași numere

Standardul cere ca al 10000-lea număr al unui mt19937 cu seed implicit să fie 4123659995, deci aceste valori sunt identice pe orice compilator.

#include <print>
#include <random>

int main() {
    std::mt19937 a(42);
    std::mt19937 b(42);
    std::println("a: {} {} {}", a(), a(), a());
    std::println("b: {} {} {}", b(), b(), b());

    std::mt19937 implicit;
    implicit.discard(9999);
    std::println("Al 10000-lea număr: {}", implicit());
    std::println("Interval: {} - {}", std::mt19937::min(), std::mt19937::max());
}

Rezultat

a: 1608637542 3421126067 4083286876
b: 1608637542 3421126067 4083286876
Al 10000-lea număr: 4123659995
Interval: 0 - 4294967295

Exemplul 2: Simulare reproductibilă

Generatorul este creat o singură dată și trimis prin referință. Generatorul std::mt19937 cu seed fix produce aceleași numere pe orice compilator, dar modul în care o distribuție le transformă nu este fixat de standard. Rezultatul de mai jos este cel dat de libc++ (Clang); cu GCC sau MSVC, același seed poate da alte valori.

#include <print>
#include <random>

int arunca(std::mt19937& gen) {
    std::uniform_int_distribution<int> zar(1, 6);
    return zar(gen);
}

int main() {
    std::mt19937 gen(2026);
    int sase = 0;
    for (int i = 0; i < 6000; ++i) {
        if (arunca(gen) == 6) {
            ++sase;
        }
    }
    std::println("6 a ieșit de {} ori din 6000 (în medie 1000)", sase);
}

Rezultat

6 a ieșit de 1092 ori din 6000 (în medie 1000)

Greșeli frecvente

  • Transmiți generatorul prin valoare (void f(std::mt19937 gen)): funcția lucrează pe o copie și dă aceleași numere la fiecare apel.
  • Faci gen() % 6 + 1: probabilitățile nu sunt perfect egale. Folosește std::uniform_int_distribution.

Comenzi înrudite

  • std::random_device: Sursă de numere aleatorii nedeterministe, oferită de sistem; folosită de obicei ca seed pentru std::mt19937.
  • std::uniform_int_distribution: Transformă numerele unui generator în întregi aleatorii dintr-un interval [a, b], toate cu aceeași probabilitate.
  • std::shuffle: Amestecă aleatoriu elementele unui interval folosind un generator de numere aleatorii.
  • std::rand: Generatorul vechi de numere pseudo-aleatorii din C (rand), inițializat cu srand; în cod nou preferă <random>.