std::discrete_distribution în C++

Alege aleatoriu un index 0, 1, 2... cu probabilități proporționale cu ponderile date.

Sintaxă
std::discrete_distribution<int> dist{p0, p1, p2, ...};
int index = dist(generator);

Ce face std::discrete_distribution

std::discrete_distribution primește o listă de ponderi și returnează indicele i cu probabilitatea pondere[i] / suma ponderilor. Ponderile nu trebuie să adune 1: {50, 30, 20} înseamnă 50%, 30% și 20%.

Este potrivit pentru extrageri ponderate: premii cu șanse diferite, alegerea unui răspuns după popularitate, evenimente din jocuri. Metoda probabilities() returnează probabilitățile normalizate.

Parametri

Parametru Descriere
p0, p1, ... Ponderile (nenegative), una pentru fiecare index.
generator La apel: un generator.

Ce returnează

La fiecare apel, un index între 0 și numărul de ponderi minus 1.

Exemple

Exemplul 1: Roata norocului

Din 10000 de învârtiri, fiecare premiu iese aproximativ proporțional cu ponderea lui. 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>
#include <string>

int main() {
    std::array<std::string, 3> premii{"Pix", "Tricou", "Telefon"};
    std::discrete_distribution<int> roata{80, 19, 1};

    std::mt19937 gen(3);
    std::array<int, 3> castigate{};
    for (int i = 0; i < 10000; ++i) {
        ++castigate[roata(gen)];
    }
    for (int i = 0; i < 3; ++i) {
        std::println("{:<8} {:>5}", premii[i], castigate[i]);
    }
}

Rezultat

Pix       7930
Tricou    1990
Telefon     80

Exemplul 2: Probabilitățile normalizate

Această parte nu depinde de generator, deci este aceeași pe orice compilator.

#include <print>
#include <random>

int main() {
    std::discrete_distribution<int> d{2, 1, 1};
    for (double p : d.probabilities()) {
        std::print("{:.2f} ", p);
    }
    std::println("");
}

Rezultat

0.50 0.25 0.25

Greșeli frecvente

  • Dai ponderi negative: comportament nedefinit.
  • Uiți că rezultatul este un index, nu valoarea: folosește-l ca poziție în vectorul cu opțiuni.

Comenzi înrudite

  • std::uniform_int_distribution: Transformă numerele unui generator în întregi aleatorii dintr-un interval [a, b], toate cu aceeași probabilitate.
  • std::bernoulli_distribution: Produce true cu probabilitatea p și false în rest: un „da sau nu” aleatoriu, ca o monedă (eventual măsluită).
  • std::sample: Alege aleatoriu n elemente distincte dintr-un interval și le copiază la destinație.