Quale dei motori di numeri casuali di <random> si dovrebbe effettivamente usare in pratica? std :: mt19937?


21

Supponiamo di voler utilizzare le funzionalità C ++ <random>in un programma pratico (per alcune definizioni di "pratico" - i vincoli qui fanno parte di questa domanda). Il codice è approssimativamente simile a questo:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

La mia domanda è: per quale tipo dovresti usare ENGINE?

  • Lo dicevo sempre std::mt19937perché era veloce digitare e aveva il riconoscimento del nome. Ma in questi giorni sembra che tutti stiano dicendo che il Mersenne Twister è molto pesante e ostile alla cache e non supera nemmeno tutti i test statistici che altri fanno.

  • Vorrei dire std::default_random_engineperché è l'ovvio "default". Ma non so se varia da piattaforma a piattaforma e non so se sia statisticamente utile.

  • Dal momento che ognuno è su una piattaforma a 64-bit in questi giorni, dovremmo almeno essere utilizzando std::mt19937_64over std::mt19937?

  • Vorrei dirlo pcg64o xoroshiro128perché sembrano rispettati e leggeri, ma non esistono <random>affatto.

  • Io non so niente di minstd_rand, minstd_rand0, ranlux24, knuth_b, ecc - di certo si deve essere buono per qualcosa?

Ovviamente ci sono alcuni vincoli concorrenti qui.

  • Forza del motore ( <random>non ha PRNG crittograficamente forti, ma alcuni di quelli standardizzati sono "più deboli" di altri, giusto?)

  • sizeof il motore.

  • La sua velocità operator().

  • Facilità di semina. mt19937è notoriamente difficile seminare correttamente perché ha così tanto stato da inizializzare.

  • Portabilità tra i fornitori di biblioteche. Se un fornitore foo_engineproduce numeri diversi da quelli di un altro fornitore foo_engine, ciò non va bene per alcune applicazioni. (Speriamo che questo non escluda nulla tranne forse default_random_engine.)

Pesando tutti questi vincoli nel miglior modo possibile, quale diresti sia la migliore risposta "best practice restando all'interno della libreria standard"? Devo continuare a usare std::mt19937o cosa?


2
All'ultimo punto, tutti gli adattatori motore standard sono specificati per restituire un determinato valore su una particolare chiamata consecutiva di quella costruita di default, quindi dovrebbero essere portatili.
1201 Programma Allarme

Risposte:


15

Riferimenti C ++ elenca tutti i motori casuali attualmente forniti da C ++. Tuttavia, la selezione dei motori lascia molto a desiderare (ad esempio, vedere il mio elenco di generatori casuali di alta qualità ). Per esempio:

  • default_random_engine è definito dall'implementazione, quindi non è noto se il motore abbia difetti statistici che potrebbero interessare all'applicazione.
  • linear_congruential_engineimplementa generatori congruenziali lineari. Tuttavia, tendono ad avere una qualità scadente a meno che il modulo non sia primo e molto grande (almeno 64 bit). Inoltre, non possono ammettere più semi del loro modulo.
  • minstd_rand0e minstd_randammettere solo circa 2 ^ 31 semi. knuth_bavvolge un minstd_rand0e fa un riordino di Bays-Durham.
  • mt19937e mt19937_64potrebbero ammettere molti più semi se fossero inizializzati meglio (ad es. inizializzando un std::seed_seqcon output multipli di random_device, non solo uno), ma usano circa 2500 byte di stato.
  • ranlux24e ranlux48usano circa 577 bit di stato ma sono lenti (funzionano mantenendo alcuni e scartando altre uscite pseudocasuali).

Tuttavia, C ++ ha anche due motori che avvolgono un altro motore per migliorare potenzialmente le sue proprietà di casualità:

  • discard_block_engine scarta alcune delle uscite di un determinato motore casuale.
  • shuffle_order_engine implementa un riordino Bays-Durham di un determinato motore casuale.

Per esempio, è possibile, ad esempio, di avere un riordino Baie-Durham di mt19937, ranlux24o un costume linear_congruential_enginecon shuffle_order_engine. Forse il motore avvolto è di qualità migliore di quello originale. Tuttavia, è difficile prevedere la qualità statistica del nuovo motore senza testarlo .

Pertanto, in attesa di tali test, sembra che mt19937sia il motore più pratico nello standard C ++ per ora. Sono a conoscenza, tuttavia, di almeno una proposta di aggiungere un altro motore di numeri casuali alle future versioni di C ++ (vedere il documento C ++ P2075 ).


1

Secondo C ++ Reference , default_random_engine:

È la selezione dell'implementazione della libreria di un generatore che fornisce un comportamento del motore almeno accettabile per un uso relativamente casuale, inesperto e / o leggero.

Quindi per un uso leggero non devi preoccuparti di nulla, semi default_random_enginecon Epoch Time (time(0))e sarebbe abbastanza bene;)


Credo che il problema qui sia la portabilità. Sebbene l'impostazione predefinita possa essere un motore che funziona bene, potrebbe non essere riproducibile su un'altra piattaforma.
bremen_matt,

@bremen_matt Hmm ... Bene, perché dobbiamo riprodurre un numero "casuale"?
Farbod Ahmadian,

2
Testing. A scopo di test, sono necessari input riproducibili. Allo stesso tempo, potresti voler o avere bisogno che quegli input siano casuali. Ad esempio, la maggior parte degli algoritmi di machine learning presuppone che i parametri vengano inizializzati in modo casuale. Ransac, CNN, DNN, ... molti algoritmi richiedono parametri casuali.
bremen_matt il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.