Como gerar números inteiros aleatórios dentro de um intervalo específico em Java?


3507

Como faço para gerar um intvalor aleatório em um intervalo específico?

Eu tentei o seguinte, mas esses não funcionam:

Tentativa 1:

randomNum = minimum + (int)(Math.random() * maximum);
// Bug: `randomNum` can be bigger than `maximum`.

Tentativa 2:

Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum =  minimum + i;
// Bug: `randomNum` can be smaller than `minimum`.

Quando você precisa de muitos números aleatórios, não recomendo a classe Random na API. Tem apenas um período muito pequeno. Experimente o twister Mersenne . Existe uma implementação Java .
Raupach

1
Antes de postar uma nova resposta, considere que já existem mais de 65 respostas para esta pergunta. Por favor, verifique se sua resposta contribui com informações que não estão entre as existentes.
janniks 03/02

Respostas:


3802

No Java 1.7 ou posterior , a maneira padrão de fazer isso é a seguinte:

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = ThreadLocalRandom.current().nextInt(min, max + 1);

Veja o JavaDoc relevante . Essa abordagem tem a vantagem de não precisar inicializar explicitamente uma instância java.util.Random , que pode ser uma fonte de confusão e erro se usada de forma inadequada.

No entanto, inversamente, não há como definir explicitamente a semente para que seja difícil reproduzir resultados em situações que sejam úteis, como testar ou salvar estados de jogos ou similares. Nessas situações, a técnica pré-Java 1.7 mostrada abaixo pode ser usada.

Antes do Java 1.7 , a maneira padrão de fazer isso é a seguinte:

import java.util.Random;

/**
 * Returns a pseudo-random number between min and max, inclusive.
 * The difference between min and max can be at most
 * <code>Integer.MAX_VALUE - 1</code>.
 *
 * @param min Minimum value
 * @param max Maximum value.  Must be greater than min.
 * @return Integer between min and max, inclusive.
 * @see java.util.Random#nextInt(int)
 */
public static int randInt(int min, int max) {

    // NOTE: This will (intentionally) not run as written so that folks
    // copy-pasting have to think about how to initialize their
    // Random instance.  Initialization of the Random instance is outside
    // the main scope of the question, but some decent options are to have
    // a field that is initialized once and then re-used as needed or to
    // use ThreadLocalRandom (if using at least Java 1.7).
    // 
    // In particular, do NOT do 'Random rand = new Random()' here or you
    // will get not very good / not very random results.
    Random rand;

    // nextInt is normally exclusive of the top value,
    // so add 1 to make it inclusive
    int randomNum = rand.nextInt((max - min) + 1) + min;

    return randomNum;
}

Veja o JavaDoc relevante . Na prática, a classe java.util.Random geralmente é preferível a java.lang.Math.random () .

Em particular, não há necessidade de reinventar a roda de geração inteira aleatória quando houver uma API direta na biblioteca padrão para realizar a tarefa.


43
Para chamadas em que o maxvalor é Integer.MAX_VALUEpossível, é possível transbordar, resultando em a java.lang.IllegalArgumentException. Você pode tentar com: randInt(0, Integer.MAX_VALUE). Além disso, se nextInt((max-min) + 1)retornar o valor mais alto (bastante raro, presumo), ele não excederá novamente (supondo que min e max sejam altos o suficiente)? Como lidar com esse tipo de situação?
Daniel

3
@MoisheLipsker Deve ser que nextLong não seja vinculado como nextInteger
mmm

13
O @leventov ThreadLocalRandomfoi adicionado ao Java dois anos e meio após a primeira pergunta. Eu sempre sou da opinião firme de que o gerenciamento da instância Random está fora do escopo da questão.
Greg Case

6
No Android Random rand = new Random ();
Webserveis

5
@Webserveis Isso é abordado nos comentários no exemplo. Versão curta - você não deve = new Random () para todas as chamadas para a função, ou seus resultados não serão suficientemente aleatórios para muitos casos.
Greg Caso

1422

Observe que essa abordagem é mais tendenciosa e menos eficiente do que uma nextIntabordagem, https://stackoverflow.com/a/738651/360211

Um padrão padrão para realizar isso é:

Min + (int)(Math.random() * ((Max - Min) + 1))

A função da biblioteca Java Math Math.random () gera um valor duplo no intervalo [0,1). Observe que esse intervalo não inclui o 1.

Para obter um intervalo específico de valores primeiro, você precisa multiplicar pela magnitude do intervalo de valores que deseja cobrir.

Math.random() * ( Max - Min )

Isso retorna um valor no intervalo [0,Max-Min), em que 'Max-Min' não está incluído.

Por exemplo, se você quiser [5,10), precisará cobrir cinco valores inteiros para usar

Math.random() * 5

Isso retornaria um valor no intervalo [0,5), em que 5 não está incluído.

Agora você precisa mudar esse intervalo para o que você está segmentando. Você faz isso adicionando o valor mínimo.

Min + (Math.random() * (Max - Min))

Agora você receberá um valor no intervalo [Min,Max). Seguindo o nosso exemplo, isso significa [5,10):

5 + (Math.random() * (10 - 5))

Mas, isso ainda não inclui Maxe você está recebendo um valor duplo. Para Maxincluir o valor, você precisa adicionar 1 ao parâmetro range (Max - Min)e truncar a parte decimal convertendo para int. Isso é realizado via:

Min + (int)(Math.random() * ((Max - Min) + 1))

E aí está. Um valor inteiro aleatório no intervalo [Min,Max]ou pelo exemplo [5,10]:

5 + (int)(Math.random() * ((10 - 5) + 1))

82
A documentação da Sun diz explicitamente que você deve usar Random () se precisar de um int em vez de Math.random () que produz um duplo.
Lilian A. Moraru

6
Na verdade, isso é tendencioso em comparação com os métodos nextInt stackoverflow.com/a/738651/360211
weston

4
"Polarizado" nesse caso significa que, após 2 ^ 53 execuções, alguns números terão uma ocultação extra, em média.
Cefalópode

378

Usar:

Random ran = new Random();
int x = ran.nextInt(6) + 5;

O número inteiro xagora é o número aleatório com um possível resultado 5-10.



137

Com eles introduziram o método ints(int randomNumberOrigin, int randomNumberBound)na Randomclasse.

Por exemplo, se você deseja gerar cinco números inteiros aleatórios (ou um único) no intervalo [0, 10], basta:

Random r = new Random();
int[] fiveRandomNumbers = r.ints(5, 0, 11).toArray();
int randomNumber = r.ints(1, 0, 11).findFirst().getAsInt();

O primeiro parâmetro indica apenas o tamanho do IntStreamgerado (que é o método sobrecarregado daquele que produz um número ilimitado IntStream).

Se você precisar fazer várias chamadas separadas, poderá criar um iterador primitivo infinito a partir do fluxo:

public final class IntRandomNumberGenerator {

    private PrimitiveIterator.OfInt randomIterator;

    /**
     * Initialize a new random number generator that generates
     * random numbers in the range [min, max]
     * @param min - the min value (inclusive)
     * @param max - the max value (inclusive)
     */
    public IntRandomNumberGenerator(int min, int max) {
        randomIterator = new Random().ints(min, max + 1).iterator();
    }

    /**
     * Returns a random number in the range (min, max)
     * @return a random number in the range (min, max)
     */
    public int nextInt() {
        return randomIterator.nextInt();
    }
}

Você também pode fazer isso por doublee longvalores. Espero que ajude! :)


1
Sugiro que você instancie o randomIterator apenas uma vez. Veja o comentário de Greg Case em sua própria resposta.
Naxos84

se você puder, você pode explicar qual é o significado do streamSize- o primeiro parâmetro deste método fornecido streamSize !=0. Qual é a diferença se streamSize1/2 / n é dado?
21818 Erfan Ahmed

104

Você pode editar seu segundo exemplo de código para:

Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum =  rn.nextInt(range) + minimum;

100

Apenas uma pequena modificação da sua primeira solução seria suficiente.

Random rand = new Random();
randomNum = minimum + rand.nextInt((maximum - minimum) + 1);

Veja mais aqui para implementação de Random


Para o mínimo <= value <maximum, fiz o mesmo com Math: randomNum = minimum + (int) (Math.random () * (maximum-minimum)); mas o elenco não é muito bom ver;)
AxelH

Resposta duplicada com pelo menos 7 anos de atraso.
Maarten Bodewes

70

ThreadLocalRandomequivalente a classe java.util.Randompara ambiente multithread. A geração de um número aleatório é realizada localmente em cada um dos encadeamentos. Portanto, temos um desempenho melhor reduzindo os conflitos.

int rand = ThreadLocalRandom.current().nextInt(x,y);

x, y- intervalos, por exemplo (1,10)


66

A Math.Randomclasse em Java é baseada em 0. Então, se você escrever algo como isto:

Random rand = new Random();
int x = rand.nextInt(10);

xserá entre 0-9inclusivo.

Portanto, considerando a seguinte matriz de 25itens, o código para gerar um número aleatório entre 0(a base da matriz) e array.lengthseria:

String[] i = new String[25];
Random rand = new Random();
int index = 0;

index = rand.nextInt( i.length );

Como i.lengthretornará 25, o nextInt( i.length )retornará um número entre o intervalo de 0-24. A outra opção é a Math.Randomque funciona da mesma maneira.

index = (int) Math.floor(Math.random() * i.length);

Para uma melhor compreensão, consulte a publicação no fórum Random Interals (archive.org) .


+1 no link da captura de tela do arquivo wayBackMachine e sua resposta ainda é uma referência útil para obter entradas "aleatórias" com um intervalo.
Tapper7

Confunde-me por que você instanciar índice para 0.
AjahnCharles

@CodeConfident A indexvariável não afetará o resultado do número aleatório. Você pode optar por inicializá-lo da maneira que desejar, sem precisar se preocupar em alterar o resultado. Espero que isto ajude.
Matt R

Exatamente ... é completamente não utilizado. Eu inicialize-o diretamente para o rand:int index = rand.nextInt(i.Length);
AjahnCharles

Ou não mesmo. int index; \n index = rand...se alguém gosta de declarações e atribuições em linhas diferentes. Alguns padrões de codificação são mais rigorosos (e sem propósito aparente) do que outros.
Mark Storer

49

Perdoe-me por ser meticuloso, mas a solução sugerida pela maioria, ou seja min + rng.nextInt(max - min + 1)), parece perigosa devido ao fato de que:

  • rng.nextInt(n)não pode alcançar Integer.MAX_VALUE.
  • (max - min)pode causar estouro quando minnegativo.

Uma solução infalível retornaria resultados corretos para qualquer min <= max um dos [ Integer.MIN_VALUE, Integer.MAX_VALUE]. Considere a seguinte implementação ingênua:

int nextIntInRange(int min, int max, Random rng) {
   if (min > max) {
      throw new IllegalArgumentException("Cannot draw random int from invalid range [" + min + ", " + max + "].");
   }
   int diff = max - min;
   if (diff >= 0 && diff != Integer.MAX_VALUE) {
      return (min + rng.nextInt(diff + 1));
   }
   int i;
   do {
      i = rng.nextInt();
   } while (i < min || i > max);
   return i;
}

Embora ineficiente, observe que a probabilidade de sucesso no while loop sempre será 50% ou superior.


Por que não lançar um IllegalArgumentException quando a diferença = Integer.MAX_VALUE? Então você não precisa do loop while.
MP Korstanje

3
@mpkorstanje Esta implementação foi projetada para funcionar com qualquer valor de min <= max, mesmo quando a diferença for igual ou maior que MAX_VALUE. A execução de um loop até o sucesso é um padrão comum nesse caso, para garantir uma distribuição uniforme (se a fonte de aleatoriedade subjacente for uniforme). Random.nextInt (int) faz isso internamente quando o argumento não é uma potência de 2.
Christian Semrau

44

Isso pode ser feito simplesmente com a declaração:

Randomizer.generate(0,10); //min of zero, max of ten

Abaixo está o código fonte

Randomizer.java

public class Randomizer {
    public static int generate(int min,int max) {
        return min + (int)(Math.random() * ((max - min) + 1));
    }
}

É apenas limpo e simples.


5
Isso poderia ter sido uma edição do outro exemplo, agora é apenas uma cópia flagrante de reputação. Apontar a "resposta com mais votos" também não é muito direto, pode mudar.
precisa

1
É isso mesmo @MaartenBodewes. Quando escrevi esta resposta, a resposta com mais votos acima ainda foi escrita como uma solução semelhante a algoritmo. Agora, a solução acima mudou muito e agora essa resposta parecia uma cópia-gato.
Abel Callejo

Realmente não entendo por que esses bits fundamentais de código não fazem parte das bibliotecas padrão Java. Por que eu tenho que implementar isso?
Leevi L


31

Vamos dar um exemplo.

Suponha que eu deseje gerar um número entre 5 e 10 :

int max = 10;
int min = 5;
int diff = max - min;
Random rn = new Random();
int i = rn.nextInt(diff + 1);
i += min;
System.out.print("The Random Number is " + i);

Vamos entender isso ...

Inicialize max com o valor mais alto e min com o valor mais baixo.

Agora, precisamos determinar quantos valores possíveis podem ser obtidos. Para este exemplo, seria:

5, 6, 7, 8, 9, 10

Portanto, a contagem disso seria max - min + 1.

ie 10 - 5 + 1 = 6

O número aleatório irá gerar um número entre 0 e 5 .

ie 0, 1, 2, 3, 4, 5

Adicionar o valor mínimo ao número aleatório produziria:

5, 6, 7, 8, 9, 10

Portanto, obtemos o intervalo desejado.



26

Gere um número aleatório para a diferença de min e max usando o método nextint (n) e adicione o número mínimo ao resultado:

Random rn = new Random();
int result = rn.nextInt(max - min + 1) + min;
System.out.println(result);

26

Eu uso isso:

 /**
   * @param min - The minimum.
   * @param max - The maximum.
   * @return A random double between these numbers (inclusive the minimum and maximum).
   */
 public static double getRandom(double min, double max) {
   return (Math.random() * (max + 1 - min)) + min;
 }

Você pode convertê-lo em um número inteiro, se desejar.


Esta função produz o mesmo número repetidamente. No meu caso, era: 2147483647
sokras

Falha: você tem uma função que requer um duplo e depois executa + 1? Isso certamente vai de encontro ao princípio da menor surpresa. O que acontece se você usar min = 0,1 e max = 0,2?
Maarten Bodewes

@sokras o método chama new Random(verifique o JavaDoc): "Cria um novo gerador de números aleatórios. Esse construtor define a semente do gerador de números aleatórios com um valor muito provável de ser distinto de qualquer outra invocação desse construtor." Muito provavelmente pode envolver apenas o uso do tempo atual como semente. Se esse tempo usar milissegundos, os computadores atuais serão rápidos o suficiente para gerar o mesmo número. Mas além disso 2147483647 é Integer.MAX_VALUE; a saída obviamente depende da entrada que você não especificou.
Maarten Bodewes

Finalmente encontrei o que realmente funciona
Jency

23

A partir do Java 7, você não deve mais usar Random. Para a maioria dos usos, o gerador de números aleatórios de sua escolha é agora ThreadLocalRandom.

Para pools de junção de forquilha e fluxos paralelos, use SplittableRandom.

Joshua Bloch. Java eficaz. Terceira edição.

A partir do Java 8

Para pools de junção de forquilha e fluxos paralelos, o uso SplittableRandomgeralmente mais rápido tem melhores propriedades de independência e uniformidade estatística em comparação com Random.

Para gerar um aleatório intno intervalo[0, 1_000]:

int n = new SplittableRandom().nextInt(0, 1_001);

Para gerar uma int[100]matriz aleatória de valores no intervalo[0, 1_000]:

int[] a = new SplittableRandom().ints(100, 0, 1_001).parallel().toArray();

Para retornar um fluxo de valores aleatórios:

IntStream stream = new SplittableRandom().ints(100, 0, 1_001);

Existe uma razão pela qual o exemplo inclui a .parallel()? Parece-me que gerar 100 números aleatórios seria muito trivial para justificar o paralelismo.
31418 Johnbot

@ Johnbot Obrigado por comentar, você está certo. Mas, o principal motivo foi mostrar uma API (é claro, o caminho inteligente é medir o desempenho antes de usar o parallelprocessamento). A propósito, para a matriz de 1_000_000elementos, a parallelversão foi duas vezes mais rápida na minha máquina em comparação com a sequencial.
27618 Oleksandr Pyrohov

21

Basta usar a classe Random :

Random ran = new Random();
// Assumes max and min are non-negative.
int randomInt = min + ran.nextInt(max - min + 1);

8
Não vejo nada de novo aqui que não tenha sido publicado em inúmeras postagens anteriores.
precisa

20

Esses métodos podem ser convenientes de usar:

Este método retornará um número aleatório entre os valores mínimo e máximo fornecidos:

public static int getRandomNumberBetween(int min, int max) {
    Random foo = new Random();
    int randomNumber = foo.nextInt(max - min) + min;
    if (randomNumber == min) {
        // Since the random number is between the min and max values, simply add 1
        return min + 1;
    } else {
        return randomNumber;
    }
}

e esse método retornará um número aleatório do valor mínimo e máximo fornecido (portanto, o número gerado também pode ser o número mínimo ou máximo):

public static int getRandomNumberFrom(int min, int max) {
    Random foo = new Random();
    int randomNumber = foo.nextInt((max + 1) - min) + min;

    return randomNumber;
}

// Since the random number is between the min and max values, simply add 1. Por quê? O min não conta? Geralmente, o intervalo é [min, max), onde min é incluído e max é excluído. Resposta errada, votada para baixo.
Maarten Bodewes

O @MaartenBodewes +1 foi adicionado porque getRandomNumberBetween gera um número aleatório exclusivo dos pontos de extremidade fornecidos.
Luke Taylor

1
O número min + 1terá duas vezes mais chances de ser o resultado do outro número getRandomNumberBetween!
Lii

19

No caso de rolar um dado, seria um número aleatório entre 1 e 6 (não entre 0 e 6), portanto:

face = 1 + randomNumbers.nextInt(6);

19
int random = minimum + Double.valueOf(Math.random()*(maximum-minimum )).intValue();

Ou dê uma olhada no RandomUtils do Apache Commons .


Isso é útil, mas tenha cuidado com uma pequena falha: as assinaturas de métodos são como: nextDouble (double startInclusive, double endInclusive), mas se você olhar dentro dos métodos, endInclusive deve ser realmente endExclusive.
Zakmck

Double.valueOf(Math.random()*(maximum-minimun)).intValue()é uma maneira bastante ofuscado (e ineficiente) para dizer (int)(Math.random()*(maximum-minimun))...
Holger

Incompatibilidade ortográfica para retorno mínimo mínimo + Double.valueOf (Math.random () * (máximo - mínimo)). IntValue ();
Hrishikesh Mishra

18

Aqui está uma classe útil para gerar aleatoriamente intsem um intervalo com qualquer combinação de limites inclusivos / exclusivos:

import java.util.Random;

public class RandomRange extends Random {
    public int nextIncInc(int min, int max) {
        return nextInt(max - min + 1) + min;
    }

    public int nextExcInc(int min, int max) {
        return nextInt(max - min) + 1 + min;
    }

    public int nextExcExc(int min, int max) {
        return nextInt(max - min - 1) + 1 + min;
    }

    public int nextIncExc(int min, int max) {
        return nextInt(max - min) + min;
    }
}

18

Para gerar um número aleatório "entre dois números", use o seguinte código:

Random r = new Random();
int lowerBound = 1;
int upperBound = 11;
int result = r.nextInt(upperBound-lowerBound) + lowerBound;

Isso fornece um número aleatório entre 1 (inclusive) e 11 (exclusivo), portanto, inicialize o valor upperBound adicionando 1. Por exemplo, se você deseja gerar um número aleatório entre 1 e 10, inicialize o número upperBound com 11 em vez de 10)


18

Você pode conseguir isso de forma concisa no Java 8:

Random random = new Random();

int max = 10;
int min = 5;
int totalNumber = 10;

IntStream stream = random.ints(totalNumber, min, max);
stream.forEach(System.out::println);

17
public static Random RANDOM = new Random(System.nanoTime());

public static final float random(final float pMin, final float pMax) {
    return pMin + RANDOM.nextFloat() * (pMax - pMin);
}

16

Outra opção é apenas usar o Apache Commons :

import org.apache.commons.math.random.RandomData;
import org.apache.commons.math.random.RandomDataImpl;

public void method() {
    RandomData randomData = new RandomDataImpl();
    int number = randomData.nextInt(5, 10);
    // ...
 }

16

Encontrei este exemplo: Gerar números aleatórios :


Este exemplo gera números inteiros aleatórios em um intervalo específico.

import java.util.Random;

/** Generate random integers in a certain range. */
public final class RandomRange {

  public static final void main(String... aArgs){
    log("Generating random integers in the range 1..10.");

    int START = 1;
    int END = 10;
    Random random = new Random();
    for (int idx = 1; idx <= 10; ++idx){
      showRandomInteger(START, END, random);
    }

    log("Done.");
  }

  private static void showRandomInteger(int aStart, int aEnd, Random aRandom){
    if ( aStart > aEnd ) {
      throw new IllegalArgumentException("Start cannot exceed End.");
    }
    //get the range, casting to long to avoid overflow problems
    long range = (long)aEnd - (long)aStart + 1;
    // compute a fraction of the range, 0 <= frac < range
    long fraction = (long)(range * aRandom.nextDouble());
    int randomNumber =  (int)(fraction + aStart);    
    log("Generated : " + randomNumber);
  }

  private static void log(String aMessage){
    System.out.println(aMessage);
  }
} 

Um exemplo de execução desta classe:

Generating random integers in the range 1..10.
Generated : 9
Generated : 3
Generated : 3
Generated : 9
Generated : 4
Generated : 1
Generated : 3
Generated : 9
Generated : 10
Generated : 10
Done.

14

É melhor usar o SecureRandom do que apenas o Random.

public static int generateRandomInteger(int min, int max) {
    SecureRandom rand = new SecureRandom();
    rand.setSeed(new Date().getTime());
    int randomNum = rand.nextInt((max - min) + 1) + min;
    return randomNum;
}

1
Isso não é tão bom, porque se for executado no mesmo milésimo de segundo, você obterá o mesmo número, precisará colocar a inicialização do rand e o setSeet fora do método.
Maraca16

Você precisa de sementes, sim, mas usando o SecureRandom.
grep

Sinto muito, mas quem rejeitou a solicitação de mudança não tem idéia da programação em Java. É uma boa sugestão, mas como está errado, porque se executado no mesmo mili segundo, dará o mesmo número, não aleatoriamente.
Maraca18

A solução correta não é em qualquer lugar para ser encontrada, muitas pessoas não sabem blocos de inicialização estáticos ... que é o que você deve usar para definir a semente: 1: private static int SecureRandom rand = new SecureRandom();2: static {3: rand.setSeed(...);4:}
maraca

5
Não há absolutamente nenhuma necessidade de semear SecureRandom, ela será semeada pelo sistema. Chamar diretamente setSeedé muito perigoso, pode substituir a semente (realmente aleatória) pela data. E isso certamente não resultará em um SecureRandom, pois qualquer um pode adivinhar o tempo e tentar propagar sua própria SecureRandominstância com essas informações.
Maarten Bodewes

13

Aqui está um exemplo simples que mostra como gerar um número aleatório de [min, max]faixa fechada , enquantomin <= max is true

Você pode reutilizá-lo como campo na classe de furos, tendo todos os Random.classmétodos em um só lugar

Exemplo de resultados:

RandomUtils random = new RandomUtils();
random.nextInt(0, 0); // returns 0
random.nextInt(10, 10); // returns 10
random.nextInt(-10, 10); // returns numbers from -10 to 10 (-10, -9....9, 10)
random.nextInt(10, -10); // throws assert

Fontes:

import junit.framework.Assert;
import java.util.Random;

public class RandomUtils extends Random {

    /**
     * @param min generated value. Can't be > then max
     * @param max generated value
     * @return values in closed range [min, max].
     */
    public int nextInt(int min, int max) {
        Assert.assertFalse("min can't be > then max; values:[" + min + ", " + max + "]", min > max);
        if (min == max) {
            return max;
        }

        return nextInt(max - min + 1) + min;
    }
}

13
rand.nextInt((max+1) - min) + min;

Isso está funcionando bem.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.