Por que parece que meu gerador de números randoms não é random em c #?

Eu estou trabalhando no Microsoft Visual C # 2008 Express.

Eu encontrei este trecho de código:

public static int RandomNumber(int min, int max) { Random random = new Random(); return random.Next(min, max); } 

O problema é que eu corri mais de 100 vezes, e está sempre me dando a mesma resposta quando meu min = 0 e max = 1. Eu recebo 0 a cada vez. (Eu criei uma function de teste para executá-lo – na verdade – estou recebendo 0 a cada vez). Estou tendo dificuldade em acreditar que é uma coincidência … há algo mais que eu possa fazer para examinar ou testar isso? (Eu fiz o teste novamente com min = 0 e max = 10 e os primeiros 50ish times, o resultado foi sempre “5”, o segundo 50ish vezes, o resultado foi sempre “9”.

?? Eu preciso de algo um pouco mais random …

-Adeena

O problema com min = 0 e max = 1 é que min é inclusivo e max é exclusivo. Portanto, o único valor possível para essa combinação é 0.

 random = new Random(); 

Isso inicia o gerador de números randoms com o tempo atual (em segundos). Quando você chama sua function muitas vezes antes que o relógio do sistema seja alterado, o gerador de números randoms é iniciado com o mesmo valor, de forma que retorne a mesma seqüência de valores.

Não crie um método de wrapper para o Next. Ele gasta ciclos criando uma nova instância da class Random. Basta usar o mesmo!

 Random myRand = new Random(); for(int i = 0; i < 10; i++) { Console.WriteLine(myRand.Next(0, 10).ToString()); } 

Isso deve lhe dar dez valores randoms.

Como já foi dito - Random é pseudo-random (como todas as implementações são), e se você criar 100 instâncias com a mesma semente, você obterá 100 instâncias dos mesmos resultados. Certifique-se de reutilizar a turma.

Além disso, como as pessoas disseram, cuidado com o fato de o MinValue ser inclusivo e o MaxValue ser exclusivo. Para o que você quer, faça myRand.Next (0, 2).

Essa sobrecarga de Next () retorna:

Um inteiro assinado de 32 bits maior ou igual a minValue e menor que maxValue; ou seja, o intervalo de valores de retorno inclui minValue, mas não MaxValue. Se minValue for igual a maxValue, minValue será retornado.

0 é o único valor possível para retornar. Talvez você queira random.NextDouble (), que retornará um double entre 0 e 1.

O min é inclusivo, mas o máximo é exclusivo. Confira a API

Você está sempre recebendo 0 porque Random.Next retorna inteiros. Você precisa chamar Random.NextDouble , que retornará um número entre 0 e 1. Além disso, você deve reutilizar sua instância Random, assim:

 [ThreadStatic] static Random random; public static Random Random { get { if (random == null) random = new Random(); return random; } } public static int RandomInteger(int min, int max) { return Random.Next(min, max); } public static double RandomDouble() //Between 0 and 1 { return Random.NextDouble(); } 

Se você quiser números randoms criptograficamente seguros, use a class RNGCryptoServiceProvider ; veja este artigo

EDIT: segurança de thread

Além do problema 0-1 já observado em outras respostas, seu problema é real quando você está procurando por um intervalo de 0-10 e obtém resultados idênticos 50 vezes seguidas.

new Random() deve retornar um número random com uma semente inicializada do timer (segundo atual), mas aparentemente você está chamando esse código 50 vezes por segundo. O MSDN sugere: “Para melhorar o desempenho, crie um Random para gerar muitos números randoms ao longo do tempo, em vez de criar repetidamente um novo Random para gerar um número random.” Se você criar seu gerador random uma vez fora do método, isso deve corrigir seu problema de “não aleatoriedade”, bem como melhorar o desempenho.

Considere também este post para um melhor gerador de números pseudo-randoms do que o fornecido pelo sistema, se você precisar de números pseudo-randoms de “maior qualidade”.

Como outros já mencionaram, o Random sendo construído várias vezes por segundo usa o mesmo segundo que o seed, então eu coloquei o construtor Random fora do seu loop e passei como parâmetro, assim:

 public static int RandomNumber(Random random, int min, int max) { return random.Next(min, max); } 

Também como mencionado por outros, o max é exclusivo, então se você quer um 0 ou 1, você deve usar [0,2] como seu [min, max], ou algum maior max e então fazer um binário AND com 1.

 public static int RandomOneOrZero(Random random) { return random.Next(0, int.MaxValue) & 1; } 

Este é um adendo a qualquer resposta, pois a resposta a esta pergunta específica é que os limites devem ser (0, 2) não (0, 1).

No entanto, se você quiser usar um método wrapper estático, deve lembrar que o Random não é thread-safe, portanto, é necessário fornecer seu próprio mecanismo de synchronization ou fornecer uma instância por thread. Aqui está uma implementação em grande parte sem bloqueio, que usa um gerador para propagar cada gerador por thread:

 public static class ThreadSafeRandom { private static readonly Random seed = new Random(); [ThreadStatic] private static Random random; public static int Next(int min, int max) { if (random == null) { lock (seed) { random = new Random(seed.Next()); } } return random.Next(min, max); } // etc. for other members } 

Você está entendendo mal a linha “random.Next (min, max)”. “min” está no lugar do menor número permitido para ser gerado aleatoriamente. Enquanto “max” está no lugar do menor número que NÃO pode ser gerado, ele não está no lugar do maior número permitido para ser desenhado. Então, quando a linha é aleatória. Em seguida (0, 1) você está basicamente permitindo que 0 seja desenhado.

Vários cartazes afirmaram que Random () usa uma semente baseada no segundo atual no relógio do sistema e qualquer outra instância de Aleatório criada no mesmo segundo terá a mesma semente. Isso está incorreto. A semente para o construtor sem parâmetros de Random é baseada na contagem de ticks ou no número de milissegundos desde o tempo de boot. Esse valor é atualizado na maioria dos sistemas aproximadamente a cada 15 milissegundos, mas pode variar dependendo das configurações do hardware e do sistema.

Eu encontrei uma maneira muito simples, mas eficaz para gerar números randoms, apenas tomando os dois últimos dígitos dos milissegundos datetime atuais:

  int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2)); int cnr = new Random(seed).Next(100); 

É grosseiro, mas funciona! 🙂

Claro que estatisticamente geraria o mesmo número a cada cem vezes. Como alternativa, você pode pegar todos os três dígitos ou concatenar com outros valores de data e hora, como segundos ou mais.

em VB eu sempre começo com a function Randomize (). Apenas chame Randomize () e execute sua function aleatória. Eu também faço o seguinte:

 Function RandomInt(ByVal lower As Integer, ByVal upper As Integer) As Integer Return CInt(Int((upper - lower + 1) * Rnd() + lower)) End Function 

Espero que isto ajude! 🙂