Pergunta

Eu gostaria de obter distribuição uniforme no intervalo [0.0, 1.0)

Se possível, por favor deixe o uso aplicação make de bytes aleatórios de / dev / urandom.

Além disso, seria bom se a sua solução era thread-safe . Se você não tiver certeza, por favor indique isso.

Consulte alguma solução eu pensava depois de ler outras respostas.

Foi útil?

Solução 2

Este parece ser bastante boa maneira:

unsigned short int r1, r2, r3;
// let r1, r2 and r3 hold random values
double result = ldexp(r1, -48) + ldexp(r2, -32) + ldexp(r3, -16);

Este se baseia na aplicação drand48 do NetBSD.

Outras dicas

simples : Um tem o dobro 52 bits de precisão assumindo IEEE. Assim gerar um bit 52 (ou maior) inteiro aleatório sem sinal (por exemplo, bytes de leitura de dev / urandom), convertê-lo em um duplo e dividi-la por dois ^ (número de bits que foi).

Isto dá uma distribuição uniforme numericamente (em que a probabilidade de um valor estar em um determinado intervalo é proporcional ao intervalo) até o dígito 52 binário.

Complicated : No entanto, há uma série de valores double no intervalo [0,1) que a lata acima não gerar. Para ser mais específico, a metade dos valores no intervalo [0,0.5) (as que têm o seu conjunto bit menos significativo) não pode ocorrer. Três quartos dos valores no intervalo [0,0.25) (as que têm um dos seus menos conjunto 2 bits) não pode ocorrer, etc, até a um e apenas um valor positivo menor do que 2 ^ -51 sendo possível, apesar de um ser duplo capaz de representar squillions de tais valores. Portanto, não pode ser dito para ser verdadeiramente uniforme em toda a faixa especificada com precisão total.

É claro que não quer escolher uma dessas duplas com igual probabilidade, porque, então, o número resultante será, em média, ser muito pequeno. Nós ainda precisamos da probabilidade do resultado estar em um determinado intervalo de ser proporcional à gama, mas com uma maior precisão no que varia que funciona para.

I pensar os seguintes trabalhos. Eu não particularmente estudado ou testado este algoritmo (como você provavelmente pode dizer pela forma como não há nenhum código), e pessoalmente eu não iria usá-lo sem encontrar referências apropriadas, indicando que é válido. Mas aqui vai:

  • Inicie o expoente fora em 52 e escolher um 52-bit inteiro sem sinal aleatório (supondo que 52 bits de mantissa).
  • Se o bit mais significativo do inteiro é 0, aumentar o expoente por um, mudar o inteiro deixado por um, e preencher o bit menos significativo com um novo bit aleatório.
  • Repita até que você bater um 1 no lugar mais significativo, ou então o expoente fica muito grande para o seu duplo (1023. Ou, eventualmente, 1022).
  • Se você encontrou um 1, divida o seu valor por 2 ^ expoente. Se você tem todos os zeros, retornar 0 (eu sei, isso não é realmente um caso especial, mas não tem destaque como muito improvável a 0 retorno é [Edit: na verdade ele pode ser um caso especial - depende se ou não você deseja gerar denorms. Se não, então uma vez que você tem 0s suficientes consecutivo nada descarte esquerda e retornar 0. Mas na prática isso é tão improvável que pode ser negligenciado, a menos que a fonte aleatório não é aleatório).

Eu não sei se há realmente qualquer utilidade prática para tal um aleatório duplo, você mente. Sua definição de aleatório deve depender de uma forma para que ele serve. Mas se você pode se beneficiar de todos os 52 de seus bits significativos sendo aleatória, isso pode realmente ser útil.

Leitura de arquivos é thread-safe AFAIK, portanto, usando fopen () para ler / dev / urandom vai render "verdadeiramente aleatório" bytes.

Embora possa haver potenciais armadilhas, METHINKS qualquer conjunto de tais bytes acessados ??como um número inteiro, dividido pelo número inteiro máximo desse tamanho, produzirá um valor de ponto flutuante entre 0 e 1, com aproximadamente aquela distribuição.

Por exemplo:

FILE* f = fopen("/dev/urandom", "r");
int32_t int;
fread(&int, sizeof(int32_t), 1, f);
fclose(f);
double theRandomValue = int / (double) (2 ** 32 - 1);

O truque é que você precisa de um randomizer 54 bits que atenda às suas necessidades. Algumas linhas de código com uma união para furar esses 54 bits no mantissa e você tem o seu número. O truque não é dupla flutuar o truque é o seu randomizer desejado.

#include <stdlib.h>
printf("%f\n", drand48());

/ dev / random:

double c;
fd = open("/dev/random", O_RDONLY);
unsigned int a, b;
read(fd, &a, sizeof(a));
read(fd, &b, sizeof(b));
if (a > b)
   c = fabs((double)b / (double)a);
else
    c = fabs((double)a / (double)b);

c é o seu valor aleatório

/ dev / urandom não é POSIX, e geralmente não está disponível.

A forma padrão de gerar uma dupla uniformemente em [0,1) é o de gerar um número inteiro no intervalo [0,2 ^ N) e divide-se por 2 ^ N. Portanto, escolha o seu gerador de números aleatórios favorito e usá-lo. Para as simulações, a minha é a Mersenne Twister , pois é extremamente rápida, mas ainda não está bem correlacionada . Na verdade, ele pode fazer isso por você, e ainda tem uma versão que vai dar mais precisão para os números menores. Normalmente você dar-lhe uma semente para começar, o que ajuda para a repetibilidade para depurar ou mostrar aos outros seus resultados. Claro, você pode ter sua garra código de um número aleatório de / dev / urandom como a semente, se não for especificado.

Para fins de criptografia que você deve usar uma das bibliotecas criptográficas padrão lá fora, ao invés, como openssl ) que vai realmente usar / dev / urandom quando disponível.

Como enfiar a segurança, a maioria não vai ser, pelo menos, com as interfaces padrão, de forma que você precisa para construir uma camada em cima, ou só usá-los em um segmento. Os que são segmento seguro tem você fornecer um estado que modificar, de modo que, em vez você está executando efetivamente múltiplos geradores não interagindo número aleatório, que pode não ser o que você está procurando.

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