[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18 Geração de Números Aleatórios

A biblioteca fornece uma grande coleção de geradores de números aleatórios que pode ser acessados através de uma interface uniforme. Variáveis de ambiente permitem a você selecionar diferentes geradores e sementes durante a execução de forma que você pode facilmente comutar entre geradores sem necessidade de recompilar seu programa. Cada instância de um gerador mantém registros de seu próprio estado, permitindo que os geradores sejam usados em programas multitarefa. Funções adicionais estão disponíveis para transformar números aleatórios uniformes em amostras de distribuições de probabilidade contínua ou discreta tais como a distribuição de Gauss, a log-normal e a de Poisson.

Essas fuinções são declaradas no arquivo de cabeçalho ‘gsl_rng.h’.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.1 Comentários gerais sobre números aleatórios

Em 1988, Park e Miller escreveram um artigo intitulado “Random number generators: good ones are hard to find.” [Commun. ACM, 31, 1192–1201]. Afortunadamente, alguns excelentes geradores de números aleatórios estão disponíveis, apesar de alguns pobres estarem ainda em uso comum. Você pode estar feliz com o gerador de números aleatórios que acompanha seu sistema operacional no seu computador, mas você deve estar consciente de que da mesma forma que os computadores tornaram-se mais rápidos, as exigências sobre os geradores de números aleatórios aumentaram. Nos dias atuais, uma simulação que chama um gerador de números aleatórios milhões de vezes pode frequentemente terminar antes que você possa descer no salão para ir na máquina de café e voltar.

Uma revisão muito boa de geradores de números aleatórios foi escrita por Pierre L’Ecuyer, no Capítulo 4 do livro: Handbook on Simulation, Jerry Banks, ed. (Wiley, 1997). O capítulo está disponível no formato postscript a partir do sítio ftp do L’Ecuyer’s (veja nas referências). O volume do Knuth sobre Seminumerical Algorithms (originalmente publicado em 1968) reserva 170 páginas para geradores de números aleatórios, e tem recentemente sido atualizado em sua 3a edição (1997). É brilhante, um clássico. Se você não o possui, você deve para a leitura imediatamente, correr até a livraria mais próxima, e comprá-lo.

Um bom gerador de números aleatórios irá satisfazer ambas as propriedades teóricas e estatísticas. Propriedades teóricas são muitas vezes difíceis de se obter (elas requerem matemática verdadeira!), mas uns preferem um gerador de números aleatórios com um período longo, baixa correlação serial, e uma tendência para não “cair principalmente sobre as partes simples.” Testes estatísticos são executados com simulações numéricas. Geralmente, um gerador de números aleatórios é usado para estimar alguma quantidade para a qual a teoria das probabilidades fornece uma resposta exata. Comparação com essa resposta exata fornece uma medida da “aleatoriedade”.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.2 A interface de Gerador de Números Aleatórios

É importante lembrar que um gerador de números aleatórios não é uma função “real” como seno e cosseno. Diferentemente de funções reais, chamadas sucessivas a um gerador de números aleatórios retorna diferentes valores de retorno. Certamente que é apenas o que você deseja para um gerador de números aleatórios, mas para alcançar esse efeito, o gerador deve manter trilha de algum tipo de variável de “estado”. Algumas vezes esse estado é apenas um inteiro (algumas vezes apenas o valor do número aleatório gerado anteriormente), mas muitas vezes é mais complicado que isso e pode envolver um vetor estático completo de números, possivelmente com alguns índices inclusos. Para usar os geradores de números aleatórios, voce não precisa conhecer os detalhes do que compreende o estado, e como esse estado varia de algoritmo para algoritmo.

A biblioteca de geradores de números aleatórios usa duas estruturas especiais, gsl_rng_type que mantém informação estática sobre cada tipo de gerador e gsl_rng que descreve uma instância de um gerador criado a partir de um dado gsl_rng_type.

As funções descritas nessa seção são declaradas no arquivo de cabeçalho ‘gsl_rng.h’.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.3 Inicialização de geradores de números aleatórios

Function: gsl_rng * gsl_rng_alloc (const gsl_rng_type * T)

Essa função retorna um apontador para a intância mais recentemente criada de um gerador de números aleatórios do tipo T. Por exemplo, o seguinte código cria uma instância do gerador de Tausworthe,

gsl_rng * r = gsl_rng_alloc (gsl_rng_taus);

se não existir memória suficiente para criar o gerador então a função retorna um apontador nulo e o controlador de erro é chamado com um código de erro de GSL_ENOMEM.

O gerador é automaticamente inicializado com a semente padrão, gsl_rng_default_seed. Essa semente é zero por padrão mas pode ser mudada ou diretamente ou através do uso da variável de ambiente GSL_RNG_SEED (veja seção Variáveis de ambiente de Números Aleatórios).

Os detalhes dos tipos de geradores de números aleatórios disponíveis são descritos mais tarde nesse capítulo.

Function: void gsl_rng_set (const gsl_rng * r, unsigned long int s)

Essa função inicializa (ou ‘semeia’) o gerador de números aleatórios. Se o gerador for semeado com o mesmo valor de s em duas diferentes execuções, o mesmo fluxo de números aleatórios irá ser gerado por sucessivas chamadas à rotina abaixo. Se diferentes valores de s >= 1 forem fornecidos, então o fluxo gerado de números aleatórios deve ser completamente diferente. Se a semente s for zero então a semente padrão da implementação original é usada ao invés do zero. Por exemplo, o código fonte Fortran original para o gerador ranlux usou uma semente de 314159265, e dessa forma fazendo s igual a zero reproduz-se a semente 314159265 quando usamos gsl_rng_ranlux.

Ao usar multiplas sementes com o mesmo gerador, escolha valores de semente maiores que zero para evitar colisões com o ajuste padrão.

Note que a maioria do geradores somente aceita sementes de 32-bit, com valores maiores sendo reduzidos módulo 2^32. Para geradores com pequenos intervalos o maior valor de semente irá ser tipicamente menor que 2^32.

Function: void gsl_rng_free (gsl_rng * r)

Essa função libera toda a memória associada ao gerador r.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.4 Fazendo amostras a partir de um gerador de números aleatórios

As seguintes funções retornam números aleatórios distribuidos uniformemente, ou como inteiros ou como números em ponto flutuante de precisão dupla. Versões modificadas dessa função são usada quando HAVE_INLINE for definida. Para obter distribuições não uniformes veja seção Distribuições de Números Aleatórios.

Function: unsigned long int gsl_rng_get (const gsl_rng * r)

Essa função retorna um inteiro aleatório a partir do gerador r. Os valores mínimo e máximo dependem do algoritmo usado, mas todos os inteiros no intervalo [min,max] são igualmente sucetíveis. Os valores de min e max podem ser determinados usando a função auxiliar gsl_rng_max (r) e gsl_rng_min (r).

Function: double gsl_rng_uniform (const gsl_rng * r)

Essa função retorna um número em ponto flutuante de precisão dupla uniformemente distribuído no intervalo [0,1). O intervalo inclui 0.0 mas exclui 1.0. O valor é tipicamente obtido dividindo o resultado de gsl_rng_get(r) por gsl_rng_max(r) + 1.0 em precisão dupla. Alguns geradores calculam essa razão internamente de forma que eles possam fornecer números em ponto flutuante com mais que 32 bits de aleatoriedade (o número máximo de bits que pode ser portávelmente representado em um simples unsigned long int).

Function: double gsl_rng_uniform_pos (const gsl_rng * r)

Essa função retorna um número em ponto flutuante de precisão dupla uniformemente distribuído no intervalo (0,1), excluindo ambos 0.0 e 1.0. O número é obtido por amostragem a partir do gerador com o algorítimo de gsl_rng_uniform até que um valor não nulo seja obtido. Você pode usar essa função se você precisa evitar uma singularidade em 0.0.

Function: unsigned long int gsl_rng_uniform_int (const gsl_rng * r, unsigned long int n)

Essa função retorna um inteiro aleatório de 0 a n-1 inclusive por meio de ajuste proporcional para baixo e/ou por descarte de amostras a partir do gerador r. Todos os inteiros no intervalo [0,n-1] são produzidos com igual probabilidade. Para geradores com um valor mínimo não nulo uma posição inicial é aplicada de forma que o zero seja retornado com a probabilidade correta.

Note que essa função é pensada para pegar amostras de intervalos menores que o intervalo do gerador básico. O parâmetro n deve ser menor que ou igual ao intervalo do gerator r. Se n for maior que o intervalo do gerador então a função chama o controlador de erro com um código de erro de GSL_EINVAL e retorna zero.

Em particular, essa função não foi pensada para gerar o intervalo completo de valores inteiros não sinalizados [0,2^32-1]. Ao invés disso escolha um gerador com o intervalo com um inteiro máximo e zero como valor mínimo, tal como gsl_rng_ranlxd1, gsl_rng_mt19937 ou gsl_rng_taus, e pegue as amostras diretamente usando gsl_rng_get. O intervalo de cada gerador pode ser encontrado usando as funções auxiliares descritas na próxima seção.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.5 Funções auxiliares aos geradores de números aleatórios

As seguintes funções fornecem informação sobre um gerador existente. Você deve usá-las preferencialmente ao invés de pegar diretamente os parâmetros do gerador dentro do próprio código fonte do gerador.

Function: const char * gsl_rng_name (const gsl_rng * r)

Essa função retorna um apontador para o nome do gerador. Por exemplo,

printf ("r é um gerador '%s'\n", 
        gsl_rng_name (r));

irá imprimir alguma coisa como r é um gerador 'taus'.

Function: unsigned long int gsl_rng_max (const gsl_rng * r)

gsl_rng_max retorna o maior valor que gsl_rng_get pode retornar.

Function: unsigned long int gsl_rng_min (const gsl_rng * r)

gsl_rng_min retorna o menor valor que gsl_rng_get pode retornar. Comumente esse valor é zero. Existe alguns geradores com algoritmos que não podem retornar zero, e para esses geradores o menor valor é 1.

Function: void * gsl_rng_state (const gsl_rng * r)
Function: size_t gsl_rng_size (const gsl_rng * r)

Essas funções retornam um apontador para o estado do gerador r e seu tamanho. Você pode usar essa informação para acessar o estado diretamente. Por exemplo, o seguinte código irá escrever o estado de um gerador para um fluxo,

void * state = gsl_rng_state (r);
size_t n = gsl_rng_size (r);
fwrite (state, n, 1, stream);
Function: const gsl_rng_type ** gsl_rng_types_setup (void)

Essa função retorna um apontador para vetor estático de todos os tipos de geradores disponíveis, terminado por um apontador nulo. A função deve ser chamada uma vez no início do programa, se for preciso. O seguinte fragmento de código mostra como iteragir sobre o vetor estático de tipos de geradores para mostrar os nomes dos algoritmos disponíveis,

const gsl_rng_type **t, **t0;

t0 = gsl_rng_types_setup ();

printf ("Available generators:\n");

for (t = t0; *t != 0; t++)
  {
    printf ("%s\n", (*t)->name);
  }

[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.6 Variáveis de ambiente de Números Aleatórios

A biblioteca permite a você escolher um gerador padrão e a semente padrão a partir das variáveis de ambiente GSL_RNG_TYPE e GSL_RNG_SEED e da função gsl_rng_env_setup. Essas três opções de escolha tornam fácil tentar diferentes geradores e diferentes sementes sem ter que recompilar seu programa.

Function: const gsl_rng_type * gsl_rng_env_setup (void)

Essa função lê as variáveis de ambiente GSL_RNG_TYPE e GSL_RNG_SEED e usa seus valores para ajustar as correspondentes variáveis de biblioteca gsl_rng_default e gsl_rng_default_seed. Essas variáveis globais são definidas como segue,

extern const gsl_rng_type *gsl_rng_default
extern unsigned long int gsl_rng_default_seed

A variável de ambiente GSL_RNG_TYPE deve ser o nome de um gerador, tal como taus ou mt19937. A variável de ambiente GSL_RNG_SEED deve conter o valor de semente desejado. Seu valor é convertido em um unsigned long int usando a função da biblioteca C strtoul.

Se você não especificar um gerador para GSL_RNG_TYPE então gsl_rng_mt19937 é usado como padrão. O valor inicial de gsl_rng_default_seed é zero.

Aqui está um programa curto que mostra como criar uma gerador global usando as variáveis de ambiente GSL_RNG_TYPE e GSL_RNG_SEED,

#include <stdio.h>
#include <gsl/gsl_rng.h>

gsl_rng * r;  /* global generator */

int
main (void)
{
  const gsl_rng_type * T;

  gsl_rng_env_setup();

  T = gsl_rng_default;
  r = gsl_rng_alloc (T);
  
  printf ("generator type: %s\n", gsl_rng_name (r));
  printf ("seed = %lu\n", gsl_rng_default_seed);
  printf ("first value = %lu\n", gsl_rng_get (r));

  gsl_rng_free (r);
  return 0;
}

Executando o programa sem quaisquer variáveis de ambiente é usado as opções padrão, um gerador mt19937 com uma semente 0,

$ ./a.out 
generator type: mt19937
seed = 0
first value = 4293858116

Ajustando as duas variáveis pela linha de comando podemos mudar o gerador padrão e a semente,

$ GSL_RNG_TYPE="taus" GSL_RNG_SEED=123 ./a.out 
GSL_RNG_TYPE=taus
GSL_RNG_SEED=123
generator type: taus
seed = 123
first value = 2720986350

[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.7 Copiando o estado do gerador de números aleatórios

Os métodos acima não expõem o ‘estado’ de número aleatório o qual modifica-se de uma chamada para outra. Ter acesso ao ‘estado’ de número aleatório é muitas vezes útil para se gravar e restaurar o estado. Para permitir essas práticas, umas poucas funções mais avançadas são fornecidas. Isso inclui:

Function: int gsl_rng_memcpy (gsl_rng * dest, const gsl_rng * src)

Essa função copia o gerador de números aleatórios src para o gerador pré-existente dest, tornando dest uma cópia exata de src. Os dois geradores devem ser do mesmo tipo.

Function: gsl_rng * gsl_rng_clone (const gsl_rng * r)

Essa função retorna um apontador para o gerador mais recentemente criado o qual é uma cópia exata do gerador r.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.8 Estado do gerador de números aleatórios - Lendo e Escrevendo

A biblioteca fornece funções para leitura e escrita do estado do número aleatório em um arquivo como dados binários.

Function: int gsl_rng_fwrite (FILE * stream, const gsl_rng * r)

Essa função escreve o estado do número aleatório do gerador de números aleatórios r para o fluxo stream em formato binário. O valor de retorno é 0 em caso de sucesso e GSL_EFAILED se houver um problema na escrita para o arquivo. Uma vez que os dados são escritos no formato binário nativo pode não ser portável entre diferentes arquiteturas.

Function: int gsl_rng_fread (FILE * stream, gsl_rng * r)

Essa função lê o estado de número aleatório do gerador de números aleatórios r a partir do fluxo aberto stream em formato binário. O gerador de números aleatórios r deve ser pré-inicializado com o tipo correto de gerador de númeos aleatórios uma vez que a informação de tipo não é gravada. O valor de retorno é 0 em caso de sucesso e GSL_EFAILED se houver um problema de leitura a partir do arquivo. Os dados são assumidos terem sido escritos no formato binário nativo sobre a mesma arquitetura.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.9 Algoritmos geradores de números aleatórios

A função descrita acima não faz referência ao algoritmo atualmente usado. Isso foi feito deliberadamente de forma que você possa mudar algoritmos sem fazer nenhuma alteração no código fonte da sua aplicação. A biblioteca fornece um grande número de geradores de diferentes tipos, incluindo simulação qualitativa de geradores, geradores fornecidos por questões de compatibilidade com outras bilbiotecas e geradores históricos do passado.

Os seguintes geradores são recomendados para uso em simulações. Eles possuem períodos extremamente longos, baixa correlação e obtêm sucesso na maioria dos teste estatísticos. Para a maioria dos códigos seguros de números não relacionados, a segunda geração de geradores RANLUX possui a mais forte demostração de aleatoriedade.

Generator: gsl_rng_mt19937

O gerador MT19937 de Makoto Matsumoto e Takuji Nishimura é uma variante do algoritmo “twisted generalized feedback shift-register”, e é conhecido como o gerador “Mersenne Twister”. Tem um período de primo de Mersenne de 2^19937 - 1 (sobre 10^6000) e é equidistribuído em 623 dimensões. Esse gerador obteve sucesso nos testes estatísticos de DIEHARD. Esse teste usa 624 palavras de estado por gerador e é comparável em valocidade a outros geradores. O gerador original usou uma semente padrão de 4357 e mudar s para zero na gsl_rng_set reproduz isso. Versões mais recentes colocaram 5489 como a semente padrão, você pode mudar isso explicitamente via gsl_rng_set ao invés de usar a semente padrão se você desejar.

Para mais informação veja,

O gerador gsl_rng_mt19937 usa a segunda revisão do procedimento de semear publicado pelos dois autores acima em 2002. O procedimento original de semeadura pode causar artefatos espúrios para alguns valores de semente. Eles estão ainda disponíveis apesar dos geradores alternativos gsl_rng_mt19937_1999 e gsl_rng_mt19937_1998.

Generator: gsl_rng_ranlxs0
Generator: gsl_rng_ranlxs1
Generator: gsl_rng_ranlxs2

O gerador ranlxs0 é uma versão de segunda geração do algoritmo RANLUX de Lüscher, o qual produz “números aleatórios luxuriosos” (43). Esse gerador fornece saídas de precisão simples (24 bits) em três níveis de luxúria ranlxs0, ranlxs1 e ranlxs2, em ordem crescente de robustez. O gerador ranlxs0 uses aritmética em ponto flutuante de precisão dupla internamente e pode ser significativamente mais rápido que a versão inteira de ranlux, particularmente sobre arquiteturas de 64-bit. O período do gerador é acima de 10^171. O algorítimo tem matematicamente comprovado propriedades e pode fornecer de forma robusta números não relacionados através de uma fórmula matemática em um dado nível de aleatoriedade. Os mais altos niveis de luxúria fornecem um incremento aos níveis de não relacionamento entre amostras como uma margem de segurança adicional.

Note que o intervalo de sementes permitidas para esse gerador é [0,2^31-1]. Maiores valores de semente são empacotados módulo 2^31.

Generator: gsl_rng_ranlxd1
Generator: gsl_rng_ranlxd2

Esses geradores produzem saídas de dupla precisão (48 bits) a partir do gerador RANLXS. A biblioteca fornece dois níveis de luxúria ranlxd1 e ranlxd2, em ordem crescente de robustez.

Generator: gsl_rng_ranlux
Generator: gsl_rng_ranlux389

O gerador ranlux é uma implementação do algoritmo original desenvolvido por Lüscher. Usa um algoritmo lagged-fibonacci-with-skipping para produzir “números aleatórios luxuriosos”. É um gerador de 24-bit, originalmente pensado para números em ponto flutuante IEEE de precisão simples. Essa implementação é baseada em aritmética inteira, enquanto as versões de segunda geração RANLXS e RANLXD descritas acima fornecem implementações em ponto flutuante que irão ser mais rápidas sobre muitas plataformas. O período do gerador é em torno de 10^171. O algoritmo tem matematicamente comprovado propriedades e pode fornecer números não relacionados em um dado nível de aleatoriedade. O nível padrão de não relacionamento recomendado por Lüscher é fornecido por gsl_rng_ranlux, enquanto gsl_rng_ranlux389 fornece o mais alto nível de aleatoriedade, com todos os 24 bits não relacionados. Ambos os tipos de gerador usam 24 palavras de estado por gerador.

Para mais informação veja,

Generator: gsl_rng_cmrg

Esse é um gerador recursivo múltiplo combinado por L’Ecuyer. Sua sequência é, onde os dois geradores básicos x_n e y_n são, com coeficientes a_1 = 0, a_2 = 63308, a_3 = -183326, b_1 = 86098, b_2 = 0, b_3 = -539608, e módulos m_1 = 2^31 - 1 = 2147483647 e m_2 = 2145483479.

O período desse gerador é lcm(m_1^3-1, m_2^3-1), que é aproximadamente 2^185 (sobre 10^56). Usa 6 palavras de estado por gerador. Para mais informação veja,

Generator: gsl_rng_mrg

Esse é um gerador recursivo múltiplo de quinta ordem por L’Ecuyer, Blouin e Coutre. Sua sequência é, com a_1 = 107374182, a_2 = a_3 = a_4 = 0, a_5 = 104480 e m = 2^31 - 1.

O período desse gerador é algo em torno de 10^46. Usa 5 palavras de estado por gerador. Mais informação pode ser encontrada no seguinte artigo,

Generator: gsl_rng_taus
Generator: gsl_rng_taus2

Esse é uma gerador de Tausworthe combinado equidistribuído maximamente por L’Ecuyer. A sequência é, onde, módulo calculado 2^32. Nas fórmulas acima ^^ denota “ou-exclusivo”. Note que o algoritmo depende das propriedades de inteiros sem sinal de 32-bit e tem sido implementado usando uma máscara de bits de 0xFFFFFFFF para fazer com que funcione sobre máquinas de 64 bit.

O período desse gerador é 2^88 (sobre 10^26). Usa 3 palavras de estado por gerador. Para mais informação veja,

O gerador gsl_rng_taus2 usa o mesmo algoritmo que gsl_rng_taus mas com um procedimento melhorado de semeadura descrito no artigo,

O gerador gsl_rng_taus2 deve agora ser usado preferêncialmente a gsl_rng_taus.

Generator: gsl_rng_gfsr4

O gerador gfsr4 é como um gerador lagged-fibonacci, e produz cada número como um somatório ou-exclusivisado de quatro valores prévios.

Ziff (referenciado abaixo) notes que “é largamente conhecido” que registros two-tap (tais como R250, que é descrito abaixo) tem falhas sérias, a mais óbvia delas sendo a correlação de três pontos que vem a partir da definição de gerador. Boas propriedades matemáticas podem ser derivadas para GFSR’s, e confirma-se numericamente que a alegação de que 4-tap GFSR’s com apropriadamente escolhidas posições iniciais são tão aleatórios quanto puder ser mensurado, usando o teste do autor.

Essa implementação usa os valores sugeridos no exemplo na p392 do artigo de Ziff: A=471, B=1586, C=6988, D=9689.

Se o valor inicial for apropriadamente escolhido (tais como os mostrados acima nessa implementação), então a sequência é dita para ser máximal; isso significa que o período é 2^D - 1, onde D é o maior lag. (É um a menos que 2^D pelo fato de não ser permitido ter todos zeros no vetor estático ra[].) Para essa implementação com D=9689 que funciona em torno de 10^2917.

Note que a implementação desse gerador usando um inteiro de 32-bit totalizando 32 implementações paralelas de geradores de um-bit. Uma concequência disso é que o período desse gerador de 32-bit é o mesmo que para o gerador de um-bit. Além disso, Essa independência significa que todos modelos de 32-bit são igualmente possíveis, e em particular que 0 é um valor aleatório permitido. (Somos gratos a Heiko Bauke por nos clarificar essas propriedade dos geradores GFSR de números aleatórios.)

Para mais informação veja,


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.10 Geradores unix de números aleatórios

Os geradores de números aleatórios padrão do Unix rand, random e rand48 são fonecidos como parte da GSL. Embora esses geradores sejam largamente disponíveis individualmente muitas vezes eles não estão todos disponíveis na mesma plataforma. Isso torna difícil escrever código portável usando-os e então incluímos o conjunto completo de geradores Unix na GSL por conveniência. Note que esses geradores não produzem aleatoriedade de alta qualidade e não são adequados para trabalhos que precisarem de estatísticas de precisão. Todavia, se você não está medindo quantidades estatísticas e apenas deseja introduzir alguma variação em seu programa então esses geradores são suficientemente aceitáveis.

Generator: gsl_rng_rand

Esse é o gerador rand do BSD. Sua sequência é com a = 1103515245, c = 12345 and m = 2^31. A semente especifica o valor inicial, x_1. O período desse gerador é 2^31, e usa 1 palavra de armazenamento por gerador.

Generator: gsl_rng_random_bsd
Generator: gsl_rng_random_libc5
Generator: gsl_rng_random_glibc2

Esses geradores implementam a família random de funções, um conjunto de “linear feedback shift register generators” originalmente usado no Unix BSD. Existem muitas versões de random em uso atualmente: a versão origina BSD (e.g. no SunOS4), uma versão libc5 (encontrada nos sistemas GNU/Linux antigos) e uma versão glibc2. Cada versão usa um procedimento de semeadura diferente, e dessa forma prosuz diferentes sequências.

As rotinas originais do BSD aceitam um espaço de armazenamento temporário de comprimento variável para o estado do gerador, com grandes espaços temporários de armazenamento fornecendo aleatoriedade de alta qualidade. A função random implementou algoritmos para comprimentos de espaço temporário de 8, 32, 64, 128 e 256 bytes, e o algoritmo com o maior comprimento que puder se ajustar no espaço temporário fornecido pelo usuário foi usado. Por compatibilidade esses algoritmos de geradores adicionais estão disponíveis com os seguinte nomes,

gsl_rng_random8_bsd
gsl_rng_random32_bsd
gsl_rng_random64_bsd
gsl_rng_random128_bsd
gsl_rng_random256_bsd

onde o sufixo numérico indica o comprimento do espaço temporário. A função random original no BSD usava um espaço temporário padrão de 128-byte e então gsl_rng_random_bsd foi feita equivalente a gsl_rng_random128_bsd. Correspondentes versões de geradores da libc5 e da glibc2 estão também disponíveis, com os nomes gsl_rng_random8_libc5, gsl_rng_random8_glibc2, etc.

Generator: gsl_rng_rand48

Esse é o gerador Unix rand48. Sua sequência é definido sobre inteiros sem sinal de 48-bit com a = 25214903917, c = 11 and m = 2^48. A semente especifica os mais altos 32 bits do valor inicial, x_1, com o mais baixo conjunto de 16 bits ajustado para 0x330E. A função gsl_rng_get retorna os mais altos 32 bits a partir de cada termo da sequência. Isso não tem um paralelismo direto nas funções rand48 originais, mas forçando o resultado para o tipo long int reproduz a saída de mrand48. A função gsl_rng_uniform usa os completos 48 bits do estado interno para retornar o número de dupla precisão x_n/m, que é equivalente à função drand48. Note que algumas versões da bilioteca C GNU possuem um erro na função mrand48 o que ocasiona a produção de diferentes resultados (somente os mais baixos 16-bits do valor de retorno foram ajustados).


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.11 Outros Geradores de Números Aleatórios

Os geradores nessa seção são fornecidos para compatibilidade com as bibliotecas existentes. Se você está convertendo um programa existente para usar a GSL então você pode selecionar esses geradores para verificar sua nova implementação comparando com o original, usando o mesmo gerador de números aleatórios. Após verificar que seu novo programa reproduz o resultado original você pode então mudar para um gerador de melhor qualidade.

Note que a maioria dos geradores nessa seção são baseados em relações congruentes lineares simples, que são o tipo menos sofisticado de gerador. Em particular, congurências lineares possuem reursos pobres quando usadas com um módulo não primo, como a maioria dessas rotinas fazem (e.g. com um expoente de módulo dois, 2^31 ou 2^32). Isso conduz a periodicidades nos menores bits significativos de cada número, com somente os bits mais altos tendo qualquer aleatoriedade. Dessa forma se você deseja produzir um fluxo de bits aleatórios é melhor evitar usar os bits significativos menores.

Generator: gsl_rng_ranf

Esse é o gerador de números aleatórios do CRAY RANF. Sua sequência é definido sobre inteiro sem sinal de 48-bit com a = 44485709377909 e m = 2^48. A semente especifica os mais baixos 32 bits do valor inicial, x_1, com o mais baixo bit ajustado para evitar que a semente assuma um valor par. Os mais altos 16 bits de x_1 são ajustados para 0. Uma consequência desse procedimento é que os pares de sementes 2 e 3, 4 e 5, etc. produzem a mesma sequência.

Esse gerador é compatível com a rotina RANF da CRAY MATHLIB. Produz números em ponto flutuante de precisão dupla o qual deve ser idêntico aos produzidos pela RANF original.

Existe uma sutileza na implementação da semeadura. O estado inicial é revertido em um passo, multiplicando pelo inverso modular de a mod m. Isso é feito para compatibilidade com a implementação original da CRAY.

Note que você pode somente semear o gerador com inteiros acima de 2^32, enquanto a implementação original CRAY usa inteiros grandes não portáveis que podem cobrir todos os 2^48 estados do gerador.

A função gsl_rng_get retorna os mais altos 32 bits de cada termo da sequência. A função gsl_rng_uniform usa os completos 48 bits para retornar o número de precisão dupla x_n/m.

O período desse gerador é 2^46.

Generator: gsl_rng_ranmar

Esse é o gerador lagged-fibonacci RANMAR de Marsaglia, Zaman e Tsang. É um gerador de 24-bit, originalmente pensado para números em ponto flutuante IEEE de precisão simples. Foi incluído na biblioteca de física de alta energia CERNLIB.

Generator: gsl_rng_r250

Esse é o gerador shift-register de Kirkpatrick e Stoll. A sequência é baseada na recorrência onde ^^ denotas “ou-exclusivo”, definido sobre palavras de 32-bit. O período desse gerador está em torno de 2^250 e usa 250 palavras de estado por gerador.

Para mais informação veja,

Generator: gsl_rng_tt800

Essa é uma antiga versão do gerador twisted generalized feedback shift-register, e tem sido substituído pelo desenvolvimento do MT19937. Todavia, ainda é um gerador aceitável por sí mesmo. Tem um período de 2^800 e usa 33 palavras de armazenagem por gerador.

Para mais informação veja,

Generator: gsl_rng_vax

Esse é o gerador VAX MTH$RANDOM. Sua sequência é, com a = 69069, c = 1 e m = 2^32. A semente especifica o valor inicial, x_1. O período desse gerador é 2^32 e usa 1 palavra de armazenamento por gerador.

Generator: gsl_rng_transputer

Esse é o gerador de números aleatórios do INMOS Transputer Development system. Sua sequência é, com a = 1664525 e m = 2^32. A semente especifica o valor inicial, x_1.

Generator: gsl_rng_randu

Esse é o gerador RANDU da IBM. Sua sequência é com a = 65539 e m = 2^31. A semente especifica o valor inicial, x_1. O período desse gerador era somente 2^29. Tem se tornado um libro texto exemplo de um gerador pobre.

Generator: gsl_rng_minstd

Esse é o gerador “mínimo padrão” de Park e Miller MINSTD, uma congruência linear simples que preocupa-se em evitar a principal armadilha de tais algoritmos. Sua sequência é, com a = 16807 e m = 2^31 - 1 = 2147483647. A semente especifica o valor inicial, x_1. O período desse gerador está em torno de 2^31.

Esse gerador era usado na biblioteca IMSL (subroutina RNUN) e no MATLAB (a função RAND) antigamente. Também algumas vezes conhecido pelo acrônimo “GGL” (Eu não sei o que significa isso).

Para mais informação veja,

Generator: gsl_rng_uni
Generator: gsl_rng_uni32

Essa é uma reimplementação do gerador de números aleatórios SLATEC de 16-bit RUNIF. Uma generalização do gerador para 32 bits é fornecida por gsl_rng_uni32. O código original está disponível a partir da NETLIB.

Generator: gsl_rng_slatec

Esse é o gerador de números aleatórios RAND da SLATEC. É antigo. O código fonte original está disponível na NETLIB.

Generator: gsl_rng_zuf

Esse é o gerador ZUFALL de séries de Fibonacci com atrazo de Peterson. Sua sequência é,

O código original está disponível a partir da NETLIB. Para mais informação veja,

Generator: gsl_rng_knuthran2

Esse é um gerador recursivo mĺtiplo de segunda ordem descrito por Knuth em Seminumerical Algorithms, 3rd Ed., page 108. Sua sequência é, com a_1 = 271828183, a_2 = 314159269, e m = 2^31 - 1.

Generator: gsl_rng_knuthran2002
Generator: gsl_rng_knuthran

Essa é um gerador recursivo múltiplo de segunda ordem descrito por Knuth em Seminumerical Algorithms, 3rd Ed., Section 3.6. Knuth fornece seu código em C. A rotina atualizada gsl_rng_knuthran2002 é a partir da nona impressão revisada e corrige alguns pontos fracos na versão anterior, o qual é implementada como gsl_rng_knuthran.

Generator: gsl_rng_borosh13
Generator: gsl_rng_fishman18
Generator: gsl_rng_fishman20
Generator: gsl_rng_lecuyer21
Generator: gsl_rng_waterman14

Esses geradores multiplicativos são tomados a partir de Knuth Seminumerical Algorithms, 3rd Ed., página 106–108. Sua sequência é, onde a semente especifica o valor inicial, x_1. Os parâmetros a e m são como segue, Borosh-Niederreiter: a = 1812433253, m = 2^32, Fishman18: a = 62089911, m = 2^31 - 1, Fishman20: a = 48271, m = 2^31 - 1, L’Ecuyer: a = 40692, m = 2^31 - 249, Waterman: a = 1566083941, m = 2^32.

Generator: gsl_rng_fishman2x

Esse é o gerador de L’Ecuyer–Fishman. É tomado a partir de Knuth Seminumerical Algorithms, 3a. Ed., página 108. Sua sequência é, com m = 2^31 - 1. x_n e y_n são fornecidos pelos algoritmos fishman20 e lecuyer21. A semente especifica o valor inicial, x_1.

Generator: gsl_rng_coveyou

Esse é o gerador de números aleatórios de Coveyou. É tomado a partir de Knuth Seminumerical Algorithms, 3a. Ed., Seção 3.2.2. Sua sequência é, com m = 2^32. A semente especifica o valor inicial, x_1.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.12 Performace

A seguinte tabela mostra o desempenho relativo de uma seleção dos geradores de números aleatórios disponíveis. Os geradores mais rápidos em simulação de qualidade são taus, gfsr4 e mt19937. Os geradores que oferecem uma qualidade comprovada matematicamente são aqueles baseados no algoritmo RANLUX.

1754 k ints/sec,    870 k doubles/sec, taus
1613 k ints/sec,    855 k doubles/sec, gfsr4
1370 k ints/sec,    769 k doubles/sec, mt19937
 565 k ints/sec,    571 k doubles/sec, ranlxs0
 400 k ints/sec,    405 k doubles/sec, ranlxs1
 490 k ints/sec,    389 k doubles/sec, mrg
 407 k ints/sec,    297 k doubles/sec, ranlux
 243 k ints/sec,    254 k doubles/sec, ranlxd1
 251 k ints/sec,    253 k doubles/sec, ranlxs2
 238 k ints/sec,    215 k doubles/sec, cmrg
 247 k ints/sec,    198 k doubles/sec, ranlux389
 141 k ints/sec,    140 k doubles/sec, ranlxd2

[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.13 Exemplos

O seguinte programa demonstra o uso de um gerador de números aleatórios para produzir números aleatórios uniformes no intervalo [0.0, 1.0),

#include <stdio.h>
#include <gsl/gsl_rng.h>

int
main (void)
{
  const gsl_rng_type * T;
  gsl_rng * r;

  int i, n = 10;

  gsl_rng_env_setup();

  T = gsl_rng_default;
  r = gsl_rng_alloc (T);

  for (i = 0; i < n; i++) 
    {
      double u = gsl_rng_uniform (r);
      printf ("%.5f\n", u);
    }

  gsl_rng_free (r);

  return 0;
}

Aqui está a saída d programa,

$ ./a.out 
0.99974
0.16291
0.28262
0.94720
0.23166
0.48497
0.95748
0.74431
0.54004
0.73995

Os números dependem da semente usada pelo gerador. A semente padrão pode ser mudada com a variável de ambiente GSL_RNG_SEED para produzir um fluxo diferente de números. O gerador propriamente dito pode ser mudado usando a variável de ambiente GSL_RNG_TYPE. Aqui está a saída do programa usando um valor de semente de 123 e o gerador recursivo múltiplo mrg,

$ GSL_RNG_SEED=123 GSL_RNG_TYPE=mrg ./a.out 
GSL_RNG_TYPE=mrg
GSL_RNG_SEED=123
0.33050
0.86631
0.32982
0.67620
0.53391
0.06457
0.16847
0.70229
0.04371
0.86374

[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.14 Referências e Leituras Adicionais

O assunto de geração de números aleatórios e sua verificação de aleatoriedade é revisado extensivamente em Knuth Seminumerical Algorithms.

Informação adicional está disponível no artigo artigo escrito por Pierre L’Ecuyer,

O código fonte para os testes DIEHARD de geradores de números aleatórios está também disponível online,

Um completo conjunto de geradores de números aleatórios está disponível a partir de NIST,


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

18.15 Agradecimentos

Agradecimentos a Makoto Matsumoto, Takuji Nishimura e Yoshiharu Kurita por fazerem o código fonte para seus geradores (MT19937, MM&TN; TT800, MM&YK) disponíveis sob a Licença Pública Geral GNU. Agradecimentos a Martin Lüscher por fornecer notas e código fonte para os geradores RANLXS e RANLXD.


[ << ] [ >> ]           [Topo] [Conteúdo] [Índice] [ ? ]

Esse documento foi gerado em 23 de Julho de 2013 usando texi2html 5.0.