Suponha que você queira usar os recursos do C ++ <random>
em um programa prático (para alguma definição de "prático" - as restrições aqui fazem parte dessa pergunta). Você tem código mais ou menos assim:
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);
}
Minha pergunta é: para que tipo você deve usar ENGINE
?
Eu costumava dizer sempre
std::mt19937
porque era rápido para digitar e tinha reconhecimento de nome. Mas hoje em dia parece que todo mundo está dizendo que o Mersenne Twister é muito pesado e hostil ao cache e nem passa em todos os testes estatísticos que os outros fazem.Eu gostaria de dizer
std::default_random_engine
porque é o óbvio "padrão". Mas não sei se isso varia de plataforma para plataforma e não sei se é estatisticamente bom.Como hoje em dia todo mundo está em uma plataforma de 64 bits, devemos pelo menos estar usando
std::mt19937_64
demaisstd::mt19937
?Eu gostaria de dizer
pcg64
ouxoroshiro128
porque eles parecem bem respeitados e leves, mas não existem<random>
.Eu não sei nada sobre
minstd_rand
,minstd_rand0
,ranlux24
,knuth_b
, etc. - certamente eles devem ser bom para alguma coisa?
Obviamente, existem algumas restrições concorrentes aqui.
Força do motor. (
<random>
não possui PRNGs criptograficamente fortes, mas ainda assim, alguns dos padronizados são "mais fracos" do que outros, certo?)sizeof
o motor.Velocidade do seu
operator()
.Facilidade de semear.
mt19937
é notoriamente difícil de propagar adequadamente porque tem muito estado para inicializar.Portabilidade entre fornecedores de bibliotecas. Se um fornecedor
foo_engine
produz números diferentes dos de outro fornecedorfoo_engine
, isso não é bom para alguns aplicativos. (Espero que isso não descarte nada, exceto talvezdefault_random_engine
.)
Pesando todas essas restrições da melhor maneira possível, o que você diria que é a melhor resposta para "melhor prática de permanecer dentro da biblioteca padrão"? Devo continuar usando std::mt19937
ou o quê?
Respostas:
A referência C ++ lista todos os mecanismos aleatórios atualmente fornecidos pelo C ++. No entanto, a seleção de motores deixa muito a desejar (por exemplo, veja minha lista de geradores aleatórios de alta qualidade ). Por exemplo:
default_random_engine
é definido pela implementação, portanto, não se sabe se o mecanismo possui falhas estatísticas com as quais o aplicativo pode se importar.linear_congruential_engine
implementa geradores congruenciais lineares. No entanto, eles tendem a ter baixa qualidade, a menos que o módulo seja primário e muito grande (pelo menos 64 bits). Além disso, eles não podem admitir mais sementes do que seu módulo.minstd_rand0
eminstd_rand
admita apenas cerca de 2 ^ 31 sementes.knuth_b
envolve umminstd_rand0
e faz um barulho de Bays-Durham.mt19937
emt19937_64
poderia admitir muito mais sementes se fossem melhor inicializadas (por exemplo, inicializando astd::seed_seq
com várias saídasrandom_device
, não apenas uma), mas elas usam cerca de 2500 bytes de estado.ranlux24
eranlux48
usam cerca de 577 bits de estado, mas são lentos (eles funcionam mantendo alguns e descartando outras saídas pseudo-aleatórias).No entanto, o C ++ também possui dois mecanismos que envolvem outro mecanismo para melhorar potencialmente suas propriedades de aleatoriedade:
discard_block_engine
descarta algumas das saídas de um determinado mecanismo aleatório.shuffle_order_engine
implementa um shuffle de Bays-Durham de um determinado mecanismo aleatório.Por exemplo, é possível, por exemplo, ter um Shuffle Bays-Durham de
mt19937
,ranlux24
ou um costumelinear_congruential_engine
comshuffle_order_engine
. Talvez o motor envolvido seja de melhor qualidade que o original. No entanto, é difícil prever a qualidade estatística do novo mecanismo sem testá-lo .Portanto, enquanto se aguarda esses testes, parece que
mt19937
é o mecanismo mais prático no padrão C ++ por enquanto. Estou ciente, no entanto, de pelo menos uma proposta para adicionar outro mecanismo de números aleatórios a versões futuras do C ++ (consulte o documento C ++ P2075 em C ++ ).fonte
De acordo com a ++ de Referência C ,
default_random_engine
:Assim, para uso leve você não precisa ser preocupar com nada, semente
default_random_engine
comEpoch Time (time(0))
e que seria bom o suficiente;)fonte