Forma recomendada para inicializar srand?

Eu preciso de uma maneira ‘boa’ para inicializar o gerador de números pseudo-randoms em C ++. Eu encontrei um artigo que afirma:

Para gerar números randoms, o srand geralmente é inicializado com algum valor distinto, como aqueles relacionados ao tempo de execução. Por exemplo, o valor retornado pelo tempo de function (declarado no header ctime) é diferente a cada segundo, o que é distinto o suficiente para a maioria das necessidades de randômico.

O Unixtime não é distinto o suficiente para o meu aplicativo. Qual é a melhor maneira de inicializar isso? Pontos de bônus se for portável, mas o código será executado principalmente em hosts Linux.

Eu estava pensando em fazer alguma matemática pid / unixtime para obter um int, ou possivelmente ler dados de /dev/urandom .

Obrigado!

EDITAR

Sim, na verdade estou iniciando meu aplicativo várias vezes por segundo e encontrei colisões.

    A melhor resposta é usar o material de número random Boost. Ou se você tiver access ao C ++ 11, use o header .

    Mas se estamos falando de rand() e srand()
    A melhor maneira é apenas usar o time() :

     int main() { srand(time(NULL)); ... } 

    Certifique-se de fazer isso no início de seu programa, e não toda vez que você ligar para rand() !

    Toda vez que você iniciar, o time () retornará um valor único (a menos que você inicie o aplicativo várias vezes por segundo). Nos sistemas de 32 bits, ele só será repetido a cada 60 anos.

    Eu sei que você não acha que o tempo é único o suficiente, mas acho difícil de acreditar. Mas eu sou conhecido por estar errado.

    Se você estiver iniciando muitas cópias do seu aplicativo simultaneamente, poderá usar um timer com uma resolução mais precisa. Mas então você corre o risco de um período de tempo mais curto antes que o valor se repita.

    OK, então se você realmente acha que está iniciando vários aplicativos por segundo.
    Em seguida, use um grão mais fino no timer.

      int main() { struct timeval time; gettimeofday(&time,NULL); // microsecond has 1 000 000 // Assuming you did not need quite that accuracy // Also do not assume the system clock has that accuracy. srand((time.tv_sec * 1000) + (time.tv_usec / 1000)); // The trouble here is that the seed will repeat every // 24 days or so. // If you use 100 (rather than 1000) the seed repeats every 248 days. // Do not make the MISTAKE of using just the tv_usec // This will mean your seed repeats every second. } 

    Isso é o que eu usei para pequenos programas de linha de comando que podem ser executados com freqüência (várias vezes por segundo):

     unsigned long seed = mix(clock(), time(NULL), getpid()); 

    Onde mix é:

     // http://www.concentric.net/~Ttwang/tech/inthash.htm unsigned long mix(unsigned long a, unsigned long b, unsigned long c) { a=ab; a=ac; a=a^(c >> 13); b=bc; b=ba; b=b^(a < < 8); c=ca; c=cb; c=c^(b >> 13); a=ab; a=ac; a=a^(c >> 12); b=bc; b=ba; b=b^(a < < 16); c=ca; c=cb; c=c^(b >> 5); a=ab; a=ac; a=a^(c >> 3); b=bc; b=ba; b=b^(a < < 10); c=ca; c=cb; c=c^(b >> 15); return c; } 

    se você precisar de um melhor gerador de números randoms, não use o libc rand. Em vez disso, use apenas algo como /dev/random ou /dev/urandom diretamente (leia em um int diretamente a partir dele ou algo parecido).

    O único benefício real do libc rand é que, dada uma semente, é previsível que ajuda na debugging.

    No windows:

     srand(GetTickCount()); 

    fornece uma melhor semente do que o time() desde a sua em milissegundos.

    A melhor maneira é usar outro gerador de números pseudo-randoms. Mersenne twister (e Wichmann-Hill) é minha recomendação.

    http://en.wikipedia.org/wiki/Mersenne_twister

    Eu sugiro que você veja o arquivo unix_random.c no código mozilla. (acho que é mozilla / security / freebl / …) deve estar na biblioteca freebl.

    lá ele usa informações de chamada do sistema (como pwd, netstat ….) para gerar ruído para o número random, ele é escrito para suportar a maioria das plataformas (o que pode me ganhar bônus: D).

    C ++ 11 random_device

    Se você precisa de qualidade razoável, então você não deveria estar usando rand () em primeiro lugar; você deve usar a biblioteca . Ele fornece muitas funcionalidades excelentes, como uma variedade de mecanismos para diferentes trocas de qualidade / tamanho / desempenho, reentrância e distribuições pré-definidas, para que você não fique enganado. Pode até fornecer access fácil a dados randoms não determinísticos (por exemplo, / dev / random), dependendo da sua implementação.

     #include  #include  int main() { std::random_device r; std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; std::mt19937 eng(seed); std::uniform_int_distribution<> dist{1,100}; for (int i=0; i<50; ++i) std::cout < < dist(eng) << '\n'; } 

    eng é uma fonte de aleatoriedade, aqui uma implementação interna do twister mersenne. Nós o propagamos usando random_device, que em qualquer implementação decente será um RNG não determanístico, e seed_seq para combinar mais de 32 bits de dados randoms. Por exemplo, em libc ++ random_device acessa / dev / urandom por padrão (embora você possa dar outro arquivo para acessar).

    Em seguida, criamos uma distribuição tal que, dada uma fonte de aleatoriedade, as chamadas repetidas para a distribuição produzirão uma distribuição uniforme de ints de 1 a 100. Então, passamos a usar a distribuição repetidamente e a imprimir os resultados.

    A verdadeira questão que você deve se perguntar é qual qualidade de aleatoriedade você precisa.

    libc random é um LCG

    A qualidade da aleatoriedade será baixa qualquer input que você forneça.

    Se você simplesmente precisa ter certeza de que instâncias diferentes terão inicializações diferentes, você pode misturar id de processo (getpid), id de thread e um timer. Misture os resultados com xor. A entropia deve ser suficiente para a maioria das aplicações.

    Exemplo:

     struct timeb tp; ftime(&tp); srand(static_cast(getpid()) ^ static_cast(pthread_self()) ^ static_cast(tp.millitm)); 

    Para melhor qualidade aleatória, use / dev / urandom. Você pode tornar o código acima portátil usando boost :: thread e boost :: date_time.

    A versão c++11 do top votou post de Jonathan Wright:

     #include  #include  #include  ... const auto time_seed = static_cast(std::time(0)); const auto clock_seed = static_cast(std::clock()); const size_t pid_seed = std::hash()(std::this_thread::get_id()); std::seed_seq seed_value { time_seed, clock_seed, pid_seed }; ... // Eg seeding an engine with the above seed. std::mt19937 gen; gen.seed(seed_value); 
     #include  #include  main() { struct timeval tv; gettimeofday(&tv,NULL); printf("%d\n", tv.tv_usec); return 0; } 

    tv.tv_usec está em microssegundos. Esta deve ser uma semente aceitável.

    Suponha que você tenha uma function com uma assinatura como:

     int foo(char *p); 

    Uma excelente fonte de entropia para uma semente aleatória é um hash dos seguintes:

    • Resultado completo de clock_gettime (segundos e nanossegundos) sem jogar fora os bits baixos – eles são os mais valiosos.
    • O valor de p , convertido em uintptr_t .
    • O endereço de p , convertido para uintptr_t .

    Pelo menos o terceiro, e possivelmente também o segundo, deriva a entropia do ASLR do sistema, se disponível (o endereço inicial da pilha e, portanto, o endereço atual da pilha, é um pouco random).

    Eu também evitaria usar rand / srand inteiramente, tanto para não tocar no estado global, e assim você pode ter mais controle sobre o PRNG que é usado. Mas o procedimento acima é uma maneira boa (e razoavelmente portátil) de obter uma entropia decente sem muito trabalho, independentemente do que o PRNG você usa.

    Para aqueles que usam o Visual Studio, aqui está outra maneira:

     #include "stdafx.h" #include  

    Talvez um pouco exagerado, mas funciona bem para intervalos rápidos. function gettimeofday encontrada aqui .

    Edit: após uma investigação mais aprofundada, o rand_s pode ser uma boa alternativa para o Visual Studio, não é apenas um rand seguro (), é totalmente diferente e não usa a semente do srand. Eu tinha presumido que era quase idêntico ao Rand apenas "mais seguro".

    Para usar rand_s apenas não se esqueça de #define _CRT_RAND_S antes de stdlib.h ser incluído.

    Contanto que seu programa esteja rodando apenas no Linux (e seu programa é um executável ELF), você tem a garantia de que o kernel fornece ao seu processo uma semente aleatória única no vetor auxiliar ELF. O kernel fornece 16 bytes randoms, diferentes para cada processo, que você pode obter com o getauxval(AT_RANDOM) . Para usá-los para srand , use apenas um int deles, como tal:

     #include  void initrand(void) { unsigned int *seed; seed = (unsigned int *)getauxval(AT_RANDOM); srand(*seed); } 

    Pode ser possível que isso também se traduza em outros sistemas baseados em ELF. Não tenho certeza de quais valores auxiliares são implementados em sistemas diferentes do Linux.

    Inclua o header no topo do seu programa e escreva:

     srand(time(NULL)); 

    Em seu programa antes de declarar seu número random. Aqui está um exemplo de um programa que imprime um número random entre um e dez:

     #include  #include  using namespace std; int main() { //Initialize srand srand(time(NULL)); //Create random number int n = rand() % 10 + 1; //Print the number cout < < n << endl; //End the line //The main function is an int, so it must return a value return 0; }