Como gerar flutuações aleatórias em C ++?
Eu pensei que poderia pegar o rand inteiro e dividi-lo por algo, isso seria suficiente?
c++
random
floating-point
hasen
fonte
fonte
random
cabeçalho adicionado no C ++ 11 é reforçada pelo documento padrão N3924: Desencorajando rand () no C ++ 14 . Incluorand()
na minha resposta a maioria das considerações históricas, mas também a realização de aplicativos herdados.<random>
cabeçalhoRespostas:
rand()
pode ser usado para gerar números pseudo-aleatórios em C ++. Em combinação comRAND_MAX
e um pouco de matemática, você pode gerar números aleatórios em qualquer intervalo arbitrário que escolher. Isso é suficiente para fins de aprendizado e programas de brinquedos. Se você precisar de números verdadeiramente aleatórios com distribuição normal, precisará empregar um método mais avançado.Isso irá gerar um número de 0,0 a 1,0, inclusive.
Isso irá gerar um número de 0,0 a alguns arbitrário
float
,X
:Isso irá gerar um número de arbitrário
LO
para arbitrárioHI
:Observe que a
rand()
função geralmente não será suficiente se você precisar de números verdadeiramente aleatórios.Antes de ligar
rand()
, você deve "propagar" o gerador de números aleatórios ligandosrand()
. Isso deve ser feito uma vez durante a execução do seu programa - não uma vez toda vez que você ligarrand()
. Isso geralmente é feito assim:Para ligar
rand
ousrand
você deve#include <cstdlib>
.Para ligar
time
, você deve#include <ctime>
.fonte
rand()
. Esta pergunta e minha resposta foram focadas especificamente no aprendizado do básico e não estavam preocupadas com altos graus de precisão. Você precisa aprender a andar antes de aprender a correr.O C ++ 11 oferece muitas novas opções com
random
. O artigo canônico sobre esse tópico seria N3551, Geração de Número Aleatório em C ++ 11Para entender por que o uso
rand()
pode ser problemático, consulte o material de apresentação rand () Considerável Nocivo de Stephan T. Lavavej, fornecido durante o evento GoingNative 2013 . Os slides estão nos comentários, mas aqui está um link direto .Também abordo
boost
e uso,rand
pois o código legado ainda pode exigir seu suporte.O exemplo abaixo é destilado do site cppreference e usa o mecanismo std :: mersenne_twister_engine e o std :: uniform_real_distribution que gera números no
[0,10)
intervalo, com outros mecanismos e distribuições comentados ( veja ao vivo ):a saída será semelhante à seguinte:
A saída variará dependendo da distribuição que você escolher, portanto, se decidirmos usar std :: normal_distribution com um valor
2
para mean e stddev, por exemplo,dist(2, 2)
a saída será semelhante a esta ( veja ao vivo ):A seguir está uma versão modificada de alguns dos códigos apresentados em
N3551
( veja ao vivo ):Os resultados serão semelhantes a:
Impulso
É claro que o Boost.Random também é sempre uma opção, aqui estou usando boost :: random :: uniform_real_distribution :
rand ()
Se você precisar usar
rand()
, podemos consultar as Perguntas frequentes sobre C, para obter um guia sobre Como gerar números aleatórios de ponto flutuante? , que basicamente fornece um exemplo semelhante a este para gerar um no intervalo[0,1)
:e gerar um número aleatório no intervalo de
[M,N)
:fonte
randMToN
pls? observe que é[M,N]
ou adicione novamente o+ 1.
item acimarandZeroToOne
. -> pensar em chamá-lo assim:randMToN(0.0, 1.0);
(N-M)
. Uma boa maneira de lidar com esse erro é encontrada aqui: stackoverflow.com/questions/33058848/…Dê uma olhada no Boost.Random . Você poderia fazer algo assim:
Brincando, é melhor passar o mesmo objeto mt19937 ao invés de construir um novo a cada vez, mas espero que você entenda.
fonte
max
, mas pode usar um open-endedmin
, você pode reverter o intervalo facilmente:return min + max - gen();
.No moderno,
c++
você pode usar o<random>
cabeçalho que acompanha o produtoc++11
.Para obter aleatórios
float
, você pode usarstd::uniform_real_distribution<>
.Você pode usar uma função para gerar os números e, se não quiser que os números sejam sempre iguais , defina o mecanismo e a distribuição
static
.Exemplo:
É ideal colocar os
float
em um recipiente comostd::vector
:Exemplo de saída:
fonte
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
é tecnicamente incorreto, 1.0 nunca será gerado, consulte pt.cppreference.com/w/cpp/numeric/random/…To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Chame o código com dois
float
valores, o código funciona em qualquer intervalo.fonte
fmaf()
(ou afma()
sobrecarga de flutuação em C ++) em C99 ou C ++ 11, que pode preservar mais precisão. Como emfmaf((float)rand() / RAND_MAX, b - a, a)
.Se você estiver usando C ++ e não C, lembre-se de que no relatório técnico 1 (TR1) e no rascunho de C ++ 0x eles adicionaram recursos para um gerador de números aleatórios no arquivo de cabeçalho, acredito que seja idêntico ao Boost. Biblioteca aleatória e definitivamente mais flexível e "moderna" que a função de biblioteca C, rand.
Essa sintaxe oferece a capacidade de escolher um gerador (como o twister de Mersenne mersenne mt19937) e depois escolher uma distribuição (normal, bernoulli, binomial etc.).
A sintaxe é a seguinte (vergonhosamente emprestado deste site ):
fonte
Em alguns sistemas (o Windows com o VC vem à mente, atualmente),
RAND_MAX
é ridiculamente pequeno, i. e apenas 15 bits. Ao dividir porRAND_MAX
você você está gerando apenas uma mantissa de 15 bits em vez dos 23 bits possíveis. Isso pode ou não ser um problema para você, mas você está perdendo alguns valores nesse caso.Ah, acabei de notar que já havia um comentário para esse problema. De qualquer forma, aqui estão alguns códigos que podem resolver isso para você:
Não testado, mas pode funcionar :-)
fonte
drand48(3)
é a maneira padrão POSIX. O GLibC também fornece uma versão reentrantedrand48_r(3)
.A função foi declarada obsoleta no SVID 3, mas nenhuma alternativa adequada foi fornecida, portanto, o IEEE Std 1003.1-2013 ainda a inclui e não possui anotações de que está indo para algum lugar em breve.
No Windows, a maneira padrão é CryptGenRandom () .
fonte
Eu não estava satisfeito com nenhuma das respostas até agora, então escrevi uma nova função de flutuação aleatória. Faz suposições bit a bit sobre o tipo de dados flutuante. Ele ainda precisa de uma função rand () com pelo menos 15 bits aleatórios.
fonte
Na minha opinião, a resposta acima fornece algum valor flutuante 'aleatório', mas nenhum deles é realmente um valor flutuante aleatório (ou seja, eles perdem uma parte da representação do valor flutuante). Antes de entrar na minha implementação, vamos primeiro dar uma olhada no formato padrão ANSI / IEEE para carros alegóricos:
| sinal (1 bit) | e (8 bits) | f (23 bits) |
o número representado por esta palavra é (-1 * sinal) * 2 ^ e * 1.f
observe que o número 'e' é um número tendencioso (com um viés 127), variando de -127 a 126. A função mais simples (e realmente mais aleatória) é simplesmente gravar os dados de um int aleatório em um float, portanto
note que se você fizer
float f = (float)rand();
isso converterá o número inteiro em um ponto flutuante (assim, 10 se tornará 10.0).Então agora, se você deseja limitar o valor máximo, pode fazer algo como (não tenho certeza se isso funciona)
mas se você olhar para a estrutura do flutuador, poderá ver que o valor máximo de um flutuador é (aproximadamente) 2 ^ 127, que é muito maior que o valor máximo de um int (2 ^ 32), excluindo assim uma parte significativa de os números que podem ser representados por um flutuador. Esta é minha implementação final:
usar esta função
randf(0, 8, 0)
retornará um número aleatório entre 0,0 e 255,0fonte
int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
e a mantissa:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
substituindo suas respectivas linhas acima. Observe que o erro da mantissa é grande: paraRAND_MAX
menores,1 << 23
você aleatoriamente selecionaria os bits mais baixos significativos e obteria 0s para os bits mais significativos o tempo todo!Se você sabe que seu formato de ponto flutuante é o IEEE 754 (quase todas as CPUs modernas, incluindo Intel e ARM), é possível construir um número de ponto flutuante aleatório a partir de um número inteiro aleatório usando métodos bit a bit. Isso só deve ser considerado se você não tiver acesso ao C ++ 11
random
ou seBoost.Random
for muito melhor.Isso fornecerá uma distribuição melhor do que aquela usando divisão.
fonte
return (float)random23 / (1 << 23)
. (Sim, eu apenas testei isso , modificando sua função para tomarrandom32
como parâmetro e executando-a para todos os valores de zero a(1 << 23)-1
. E sim, seu método realmente fornece exatamente os mesmos resultados que a divisão por1 << 23
.)Para C ++, ele pode gerar números reais de flutuação dentro do intervalo especificado pela
dist
variávelfonte
rand () retorna um int entre 0 e RAND_MAX. Para obter um número aleatório entre 0,0 e 1,0, primeiro converta o retorno int por rand () para um ponto flutuante e depois divida por RAND_MAX.
fonte
Não consegui postar duas respostas, então aqui está a segunda solução. números aleatórios log2, viés massivo em direção a 0,0f, mas é realmente uma flutuação aleatória de 1,0f a 0,0f.
fonte