Como imprimir um numero com a classe Random entre -1 e 1?

Fiz assim mas dá sempre numeros entre -1 e 0,e quero entre -1 e 1.

public class Random{
  public static void main(String[] args) {
    System.out.println(Math.random()-1);
  }
}
Random r = new Random();
System.out.println(r.ints(-1, 2).findFirst().getAsInt());
1 curtida

O método Math.random() gera um valor do tipo double no intervalo 0 (inclusive) e 1 (exclusive), sendo assim, vc precisa ajustar isso, multiplicando por um valor que limitará superiormente o intervalo. Como você quer que o intervalo englobe o seu limite superior, vc precisa somar 1. Por exemplo:

double n1 = Math.random() * 5; // gera um double entre 0 (inclusive) e 5 (exclusive)
double n2 = Math.random() * ( 5 + 1 ); // gera um double entre 0 (inclusive) e 5 (inclusive)

A soma do 1 ali com o 5 é para você entender a ideia. Agora, vc precisa de um inteiro, então é só fazer um cast do double gerado para um int.

int n = (int) ( Math.random() * ( 5 + 1 ) ); // gera um int entre 0 (inclusive) e 5 (inclusive)

Como você quer variar o limite inferior também, vc precisa calcular quantas unidades existem entre seu limite inferior e o limite superior, ou seja, a distância entre esses dois valores. Por exemplo, se quiser gerar entre 5 e 12, vc precisa calcular a distância entre os dois (12 - 5 = 7). Fazendo:

 int distancia = 12 - 5;
 int n = (int) ( Math.random() * ( distancia ) ); // gera um valor entre 0 (inclusive) e 7 (exclusive)

Se vc somar o valor gerado à 5, você terá um valor entre 5 (inclusive) e 12 (exclusive), então vc precisa somar 1 à distância para englobar seu limite superior:

int distancia = 12 - 5;
int n = (int) ( Math.random() * ( distancia + 1 ) ); // gera um valor entre 0 (inclusive) e 7 (inclusive)

Agora, se vc somar o valor gerado à 5, você terá um valor entre 5 (inclusive) e 12 (inclusive), que é o que você quer. Pronto, basta colocar tudo isso em um método para parametrizar os limites e retornar o valor do intervalo fechado.

public static void main( String[] args ) {
    
    for ( int i = 0; i < 10; i++ ) {
        System.out.println( intervalRandom( -1, 1 ) );
    }
    
}

public static int intervalRandom( int limiteInferior, int limiteSuperior ) {
    if ( limiteInferior > limiteSuperior ) {
        int temp = limiteSuperior;
        limiteSuperior = limiteInferior;
        limiteInferior = temp;
    }
    int distancia = limiteSuperior - limiteInferior;
    return limiteInferior + (int) ( Math.random() * ( distancia + 1 ) );
}

A solução do @Lucas_Camara funciona e vai direto ao ponto usando streams, mas eu fiquei com a pulga atrás da orelha em relação à performance. Fiz um teste aqui meio bruto e é rápido igual, mas tem que tomar um certo cuidado, ainda mais se a essa geração de números que você precisa for ser utilizada massivamente.

public static void main( String[] args ) {
    
    Random r = new Random();
    
    long t1 = 0;
    long t2 = 0;
    long t3 = 0;
    
    for ( int i = 0; i < 1000; i++ ) {
        
        t1 = System.currentTimeMillis();
        
        for ( int j = 0; j < 100000; j++ ) {
            r.ints( -20000, 20000 ).findFirst().getAsInt();
        }

        t2 = System.currentTimeMillis();
        
        for ( int j = 0; j < 100000; j++ ) {
            intervalRandom( -20000, 20000 );
        }
        
        t3 = System.currentTimeMillis();

    }
    
    System.out.println( t2 - t1 );
    System.out.println( t3 - t2 );
    
    
}

public static int intervalRandom( int limiteInferior, int limiteSuperior ) {
    if ( limiteInferior > limiteSuperior ) {
        int temp = limiteSuperior;
        limiteSuperior = limiteInferior;
        limiteInferior = temp;
    }
    int distancia = limiteSuperior - limiteInferior;
    return limiteInferior + (int) ( Math.random() * ( distancia + 1 ) );
}

Só tome o cuidado de não instanciar um novo Random toda vez que for gerar o valor, senão o desempenho cai:

public static void main( String[] args ) {
    
    long t1 = 0;
    long t2 = 0;
    long t3 = 0;
    
    for ( int i = 0; i < 1000; i++ ) {
        
        t1 = System.currentTimeMillis();
        
        for ( int j = 0; j < 100000; j++ ) {
            Random r = new Random();
            r.ints( -20000, 20000 ).findFirst().getAsInt();
        }

        t2 = System.currentTimeMillis();
        
        for ( int j = 0; j < 100000; j++ ) {
            intervalRandom( -20000, 20000 );
        }
        
        t3 = System.currentTimeMillis();

    }
    
    System.out.println( t2 - t1 );
    System.out.println( t3 - t2 );
    
    
}

public static int intervalRandom( int limiteInferior, int limiteSuperior ) {
    if ( limiteInferior > limiteSuperior ) {
        int temp = limiteSuperior;
        limiteSuperior = limiteInferior;
        limiteInferior = temp;
    }
    int distancia = limiteSuperior - limiteInferior;
    return limiteInferior + (int) ( Math.random() * ( distancia + 1 ) );
}

Para finalizar, no benchmark poderia até ter feito a média dos tempos, mas eu preferi pegar a diferença só da última geração, pq teoricamente já houve tempo de rolar o warm-up do algoritmo.

3 curtidas

Como Math.random() retorna um double, acredito que você queira um double como resultado (mas se quiser um int, use o que já foi sugerido acima).

Enfim, você pode usar um java.util.concurrent.ThreadLocalRandom:

import java.util.concurrent.ThreadLocalRandom;

...
System.out.println(ThreadLocalRandom.current().nextDouble(-1, 1));

Ou um java.util.Random (e neste caso eu sugiro que mude o nome da sua classe, para evitar colisão de nomes):

Random r = new Random();
double randomValue = (2 * r.nextDouble()) - 1;

// ou, a partir do Java 8
Random r = new Random();
double valor = r.doubles(-1, 1).findFirst().getAsDouble();
2 curtidas

obrigado!!

obrigado!

Obrigado!