Mi sembra di vedere molte risposte in cui qualcuno suggerisce di utilizzare <random>
per generare numeri casuali, di solito insieme a codice come questo:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
Di solito questo sostituisce una sorta di "abominio empio" come:
srand(time(NULL));
rand()%6;
Potremmo criticare il vecchio modo sostenendo che time(NULL)
fornisce bassa entropia, time(NULL)
è prevedibile e il risultato finale non è uniforme.
Ma tutto questo è vero per il nuovo modo: ha solo un rivestimento più brillante.
rd()
restituisce un singolounsigned int
. Questo ha almeno 16 bit e probabilmente 32. Non è sufficiente per seminare i 19937 bit di stato di MT.L'utilizzo
std::mt19937 gen(rd());gen()
(seeding con 32 bit e guardando il primo output) non fornisce una buona distribuzione dell'output. 7 e 13 non possono mai essere la prima uscita. Due semi producono 0. Dodici semi producono 1226181350. ( Link )std::random_device
può essere, e talvolta lo è, implementato come un semplice PRNG con un seed fisso. Potrebbe quindi produrre la stessa sequenza in ogni esecuzione. ( Link ) Questo è anche peggio ditime(NULL)
.
Peggio ancora, è molto facile copiare e incollare gli snippet di codice precedenti, nonostante i problemi che contengono. Alcune soluzioni a questo richiedono l'acquisizione di biblioteche di grandi dimensioni che potrebbero non essere adatte a tutti.
Alla luce di ciò, la mia domanda è: come si può seminare in modo succinto, portabile e completo il PRNG mt19937 in C ++?
Dati i problemi di cui sopra, una buona risposta:
- Deve seminare completamente il mt19937 / mt19937_64.
- Non posso fare affidamento esclusivamente su
std::random_device
otime(NULL)
come fonte di entropia. - Non dovrebbe fare affidamento su Boost o altre biblioteche.
- Dovrebbe rientrare in un piccolo numero di righe in modo tale da sembrare piacevole da copiare e incollare in una risposta.
Pensieri
Il mio pensiero attuale è che gli output di
std::random_device
possono essere combinati (forse tramite XOR) contime(NULL)
valori derivati dalla randomizzazione dello spazio degli indirizzi e una costante hard-coded (che potrebbe essere impostata durante la distribuzione) per ottenere il massimo sforzo con l'entropia.std::random_device::entropy()
non fornisce una buona indicazione di ciò chestd::random_device
potrebbe o non potrebbe fare.
std::random_device
, time(NULL)
e indirizzi di funzioni, quindi XOR insieme per produrre una sorta di fonte di entropia di massimo sforzo.
std::random_device
correttamente sulle piattaforme su cui prevedi di eseguire il tuo programma e fornire una funzione di supporto che crea un generatore seeded ( seed11::make_seeded<std::mt19937>()
)