Pergunta

Eu vi algumas recomendações para não semear geradores de números pseudo-aleatórios mais de uma vez por execução, mas nunca acompanhada por uma explicação completa. Claro, é fácil ver porque o seguinte exemplo (C / C ++) não é uma boa idéia:

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

desde chamando get_rand várias vezes por resultados segundo produz repetidas.

Mas não seria o exemplo a seguir ainda ser uma solução aceitável?

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() << " ";
  }
}

i. embora MyRand: s construtor é chamado várias vezes em rápida sucessão, cada chamada para srand tem um parâmetro diferente. Obviamente, isso não é thread-safe, mas mais uma vez não é rand.

Foi útil?

Solução

Cada vez que você chamar uma função gerador de números pseudo-aleatórios, o gerador leva algum estado interno e produz um número pseudo-aleatório e um novo estado interno. O algoritmo para transformar o estado interno é cuidadosamente escolhido para que a saída parece aleatória.

Quando você semear o gerador de números aleatórios, você está definindo basicamente este estado interno. Se você redefinir o estado interno para algum valor previsível, você vai perder a aparência de aleatoriedade.

Por exemplo, um popular RNG, simples é um gerador de congruência linear. Os números são gerados como esta:

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

Neste caso, X [n + 1] é tanto o resultado e o novo estado interno. Se você semear o gerador de cada vez como você sugere acima, você vai ter uma seqüência parecida com esta:

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

onde b é o seu seed_base. Isso não parece aleatória em tudo.

Outras dicas

Se a sua semente é previsível, o que ele está aqui desde que você está apenas incrementá-lo, a saída do rand () irá também ser previsível.

Ela realmente depende de por que você quer para gerar números aleatórios, e como "aleatório" é um aleatório aceitável para você. No seu exemplo, pode evitar duplicatas em rápida sucessão, e isso pode ser bom o suficiente para você. Afinal de contas, o que importa é que ele é executado.

Em quase todas as plataformas existe uma melhor maneira de gerar números aleatórios que rand ().

Bem, é o processamento extra que não precisa ser feito.

Nesse cenário que eu tinha acabado de chamar o construtor uma vez com uma semente baseada no tempo antes do início do loop. Isso vai garantir resultados aleatórios, sem a sobrecarga extra de mudar sementes para cada iteração.

Eu não acho que o seu método é qualquer mais aleatória do que isso.

Você pode pensar em geração de números aleatórios (isto não é rigorosamente verdade implementação-wise mais, mas serve como uma ilustração) como uma tabela de valores. Se você se lembrar de fazer qualquer dessas coisas nas estatísticas para fazer amostras aleatórias simples, uma semente basicamente diz-lhe que linha e coluna para começar a sua grande mesa de números aleatórios. Reseeding uma e outra vez é simplesmente desnecessário uma vez que já pode supor que os números são normalmente já distribuído.

Não há simplesmente nenhum benefício adicional para semear mais de uma vez desde que este deve ser bom o suficiente (dependendo da aplicação). Se você precisa fazer "mais" números aleatórios, existem muitos métodos de geração de números aleatórios. Um caso que eu posso pensar é para gerar números aleatórios de uma forma thread-safe.

Enquanto a solução é aceitável, seus números haverá mais aleatória do que semear uma vez, a nível mundial. srand geralmente não deve pertencer a um construtor. Se você gostaria de apoiar números aleatórios, semente de uma vez quando o programa inicia, e esquecê-la.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top