std::uniform_int_distribution în C++

Transformă numerele unui generator în întregi aleatorii dintr-un interval [a, b], toate cu aceeași probabilitate.

Sintaxă
std::uniform_int_distribution<int> dist(a, b);
int x = dist(generator);

Ce face std::uniform_int_distribution

std::uniform_int_distribution<T>(a, b) produce întregi între a și b, inclusiv ambele capete, fiecare cu aceeași șansă. Spre deosebire de rand() % n, distribuția este corectă pentru orice interval.

Distribuția nu generează singură numere: o apelezi cu un generator, dist(gen). Poți folosi aceeași distribuție de câte ori vrei. Cu un seed fix rezultatul este reproductibil pe același compilator, dar valorile concrete pot diferi între libc++, libstdc++ și MSVC.

Parametri

Parametru Descriere
a, b Capetele intervalului, ambele incluse (a <= b).
generator La apel: un generator, de exemplu std::mt19937.

Ce returnează

La fiecare apel dist(gen), un întreg din [a, b].

Exemple

Exemplul 1: Zar și cod de verificare

#include <print>
#include <random>

int main() {
    std::mt19937 gen(std::random_device{}());

    std::uniform_int_distribution<int> zar(1, 6);
    std::uniform_int_distribution<int> cod(100000, 999999);

    std::println("Zar: {}", zar(gen));
    std::println("Cod de verificare: {}", cod(gen));
}

Rezultat posibil (diferă la fiecare rulare)

Zar: 5
Cod de verificare: 472913

Exemplul 2: Frecvența fiecărei fețe (seed fix)

Din 60000 de aruncări, fiecare față apare în jur de 10000 de ori. 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 <array>
#include <print>
#include <random>

int main() {
    std::mt19937 gen(1);
    std::uniform_int_distribution<int> zar(1, 6);

    std::array<int, 7> frecventa{};
    for (int i = 0; i < 60000; ++i) {
        ++frecventa[zar(gen)];
    }
    for (int fata = 1; fata <= 6; ++fata) {
        std::println("{}: {}", fata, frecventa[fata]);
    }
}

Rezultat

1: 10008
2: 9957
3: 10021
4: 10036
5: 9959
6: 10019

Exemplul 3: Un element aleatoriu dintr-un vector

Intervalul este de la 0 la size() - 1, ambele incluse. 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>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> citate{"Carpe diem", "Festina lente", "Veni, vidi, vici"};

    std::mt19937 gen(7);
    std::uniform_int_distribution<std::size_t> index(0, citate.size() - 1);
    std::println("Citatul zilei: {}", citate[index(gen)]);
}

Rezultat

Citatul zilei: Carpe diem

Greșeli frecvente

  • Scrii uniform_int_distribution<int>(0, v.size()): capătul de sus este inclus, deci uneori primești un index în afara vectorului.
  • Folosești uniform_int_distribution<char>: nu este permis de standard (doar short, int, long și variantele lor). Generează un int și convertește-l.

Comenzi înrudite

  • std::mt19937: Generatorul Mersenne Twister: numere pseudo-aleatorii rapide și de calitate, reproductibile cu un seed fix.
  • std::uniform_real_distribution: Produce numere cu virgulă aleatorii, distribuite uniform în intervalul [a, b).
  • std::discrete_distribution: Alege aleatoriu un index 0, 1, 2… cu probabilități proporționale cu ponderile date.
  • std::random_device: Sursă de numere aleatorii nedeterministe, oferită de sistem; folosită de obicei ca seed pentru std::mt19937.