Vorrei completare le eccellenti risposte di Angry Shoe e Peterchen con una breve panoramica dello stato dell'arte nel 2015:
Alcune buone scelte
randutils
La randutils
libreria (presentazione) è una novità interessante, che offre un'interfaccia semplice e capacità casuali (dichiarate) robuste. Ha gli svantaggi che aggiunge una dipendenza dal tuo progetto e, essendo nuovo, non è stato ampiamente testato. Ad ogni modo, essendo gratuito (licenza MIT) e solo header, penso che valga la pena provare.
Campione minimo: un tiro di dado
#include <iostream>
#include "randutils.hpp"
int main() {
randutils::mt19937_rng rng;
std::cout << rng.uniform(1,6) << "\n";
}
Anche se non si è interessati alla libreria, il sito web ( http://www.pcg-random.org/ ) fornisce molti articoli interessanti sul tema della generazione di numeri casuali in generale e sulla libreria C ++ in particolare.
Boost.Random
Boost.Random
(documentazione) è la libreria che ha ispirato C++11
's <random>
, con il quale condivide gran parte dell'interfaccia. Sebbene teoricamente sia anche una dipendenza esterna, Boost
ha ormai uno status di libreria "quasi standard" e il suo Random
modulo potrebbe essere considerato come la scelta classica per la generazione di numeri casuali di buona qualità. Presenta due vantaggi rispetto alla C++11
soluzione:
- è più portabile, richiede solo il supporto del compilatore per C ++ 03
- i suoi
random_device
metodi usi specifici del sistema a offerta semina di buona qualità
L'unico piccolo difetto è che l'offerta del modulo random_device
non è solo di intestazione, bisogna compilare e collegare boost_random
.
Campione minimo: un tiro di dado
#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>
int main() {
boost::random::random_device rand_dev;
boost::random::mt19937 generator(rand_dev());
boost::random::uniform_int_distribution<> distr(1, 6);
std::cout << distr(generator) << '\n';
}
Sebbene il campione minimo funzioni bene, i programmi reali dovrebbero utilizzare un paio di miglioramenti:
- fare
mt19937
a thread_local
: il generatore è abbastanza grassoccio (> 2 KB) ed è meglio non allocarlo nello stack
- seme
mt19937
con più di un numero intero: il Mersenne Twister ha uno stato grande e può beneficiare di una maggiore entropia durante l'inizializzazione
Alcune scelte non proprio buone
La libreria C ++ 11
Pur essendo la soluzione più idiomatica, la <random>
libreria non offre molto in cambio della complessità della sua interfaccia anche per le esigenze di base. Il difetto è std::random_device
: lo Standard non impone alcuna qualità minima per il suo output (a patto che entropy()
ritorni 0
) e, a partire dal 2015, MinGW (non il compilatore più utilizzato, ma difficilmente una scelta esoterica) stamperà sempre 4
sul campione minimo.
Campione minimo: un tiro di dado
#include <iostream>
#include <random>
int main() {
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(1, 6);
std::cout << distr(generator) << '\n';
}
Se l'implementazione non è marcio, questa soluzione dovrebbe essere equivalente a quella Boost e valgono gli stessi suggerimenti.
La soluzione di Godot
Campione minimo: un tiro di dado
#include <iostream>
#include <random>
int main() {
std::cout << std::randint(1,6);
}
Questa è una soluzione semplice, efficace e pulita. Unico difetto, la compilazione richiederà un po 'di tempo - circa due anni, a condizione che C ++ 17 venga rilasciato in tempo e la randint
funzione sperimentale sia approvata nel nuovo standard. Forse a quel punto anche le garanzie sulla qualità della semina miglioreranno.
Campione minimo: un tiro di dado
#include <cstdlib>
#include <ctime>
#include <iostream>
int main() {
std::srand(std::time(nullptr));
std::cout << (std::rand() % 6 + 1);
}
La vecchia soluzione C è considerata dannosa e per buone ragioni (vedi le altre risposte qui o questa analisi dettagliata ). Tuttavia, ha i suoi vantaggi: è semplice, portabile, veloce e onesto, nel senso che è noto che i numeri casuali che si ottengono sono difficilmente decenti, e quindi non si è tentati di usarli per scopi seri.
La soluzione dei troll contabili
Campione minimo: un tiro di dado
#include <iostream>
int main() {
std::cout << 9; // http://dilbert.com/strip/2001-10-25
}
Sebbene il 9 sia un risultato alquanto insolito per un normale tiro di dado, si deve ammirare l'eccellente combinazione di buone qualità in questa soluzione, che riesce ad essere la più veloce, più semplice, più adatta alla cache e più portatile. Sostituendo 9 con 4 si ottiene un generatore perfetto per qualsiasi tipo di Dungeons and Dragons die, pur evitando i valori carichi di simboli 1, 2 e 3. L'unico piccolo difetto è che, a causa del cattivo umore dei troll contabili di Dilbert, questo programma genera effettivamente un comportamento indefinito.