Domanda

Ho visto un paio di consigli per non semina pseudo-random number generators più di una volta ogni esecuzione, ma mai accompagnate da una spiegazione approfondita.Naturalmente, è facile capire perché i seguenti (C/C++), ad esempio, non è una buona idea:

int get_rand() {
  srand(time(NULL));
  return rand();
}

dalla chiamata get_rand più volte al secondo produce ripetuto risultati.

Ma non sarebbe il seguente esempio ancora essere una soluzione accettabile?

MyRand.h

#ifndef MY_RAND_H
#define MY_RAND_H

class MyRand
{
  public:
    MyRand();
    int get_rand() const;
  private:
    static unsigned int seed_base;
};

#endif

MyRand.cpp

#include <ctime>
#include <cstdlib>
#include "MyRand.h"

unsigned int MyRand::seed_base = static_cast<unsigned int>(time(NULL));

MyRand::MyRand()
{
  srand(seed_base++);
}

int MyRand::get_rand() const
{
  return rand();
}

main.cpp

#include <iostream>
#include "MyRand.h"

int main(int argc, char *argv[]) 
{
  for (int i = 0; i < 100; i++) 
  {
    MyRand r;
    std::cout << r.get_rand() << " ";
  }
}

cioèanche se MyRand:s costruttore viene chiamato più volte in rapida successione, ogni chiamata a srand ha un parametro diverso.Ovviamente, questo non è thread-safe, ma poi di nuovo, né è rand.

È stato utile?

Soluzione

Ogni volta che si chiama una funzione di generatore di numeri pseudo-casuali, il generatore richiede qualche stato interno e produce un numero pseudo-casuale e un nuovo stato interno. L'algoritmo per trasformare lo stato interno è scelto con cura in modo da l'uscita appare casuale.

Quando si inizializzare il generatore di numeri casuali, si sta fondamentalmente l'impostazione di questo stato interno. Se si ripristina lo stato interno di un certo valore prevedibile, si perde l'aspetto della casualità.

Per esempio, un popolare, semplice RNG è un generatore congruenziale lineare. I numeri vengono generati in questo modo:

X[n+1] = (a X[n] + c) mod m

In questo caso, X [n + 1] è sia il risultato e il nuovo stato interno. Se si inizializzare il generatore ogni volta come lei suggerisce sopra, si otterrà una sequenza che assomiglia a questo:

{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...}

dove b è la tua seed_base. Questo non sembra casuale a tutti.

Altri suggerimenti

Se il seme è prevedibile, che è qui da quando sei solo incrementandolo, l'uscita da rand () sarà anche prevedibile.

In realtà dipende il motivo per cui si desidera generare numeri casuali, e in che modo "random" è un caso accettabile per voi. Nel tuo esempio, può evitare i duplicati in rapida successione, e che può essere abbastanza buono per voi. Dopo tutto, ciò che conta è che funziona.

Su quasi ogni piattaforma c'è un modo migliore per generare numeri casuali di rand ().

Beh, è un'ulteriore elaborazione che non ha bisogno di essere fatto.

In questo scenario mi basta chiamare il costruttore di una volta, con un tempo a base di seme prima dell'inizio del ciclo.Avrà la garanzia di risultati casuali, senza il sovraccarico aggiuntivo di modifica di semi per ogni iterazione.

Io non credo che il tuo metodo di qualsiasi più casuale di che.

Si può pensare di generazione di numeri casuali (questo non è assolutamente vero implementazione-saggio più, ma serve come un esempio), come una tabella di valori. Se vi ricordate di fare qualsiasi di queste cose nelle statistiche per fare campioni casuali semplici, un seme in sostanza ti dice cosa riga e colonna a partire dal numero nella grande tavolo di numeri casuali. Risemina più e più volte è semplicemente inutile dal momento che possiamo già ipotizzare che i numeri sono normalmente già distribuite.

Non c'è alcun vantaggio di semina più di una volta dal momento che questo dovrebbe essere abbastanza buono (a seconda dell'applicazione). Se avete bisogno di "più" numeri casuali, ci sono molti metodi di generazione di numeri casuali. Un caso che mi viene in mente è quello di generare numeri casuali in un modo thread-safe.

Mentre la soluzione è accettabile, i numeri non sarà più casuale di semina una volta, a livello globale. srand in genere non dovrebbe appartenere a un costruttore. Se vuoi supportare numeri casuali, seminare una volta all'avvio del programma, e non pensarci più.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top