2010-03-30 9 views
99

La clase aleatoria tiene un método para generar int aleatorio en un rango determinado. Por ejemplo:Java: número largo aleatorio en 0 <= x <n rango

Random r = new Random(); 
int x = r.nextInt(100); 

Esto generaría un número int más o igual que 0 y menor que 100. Me gustaría hacer exactamente lo mismo con el número de largo.

long y = magicRandomLongGenerator(100); 

La clase aleatoria solo tiene nextLong(), pero no permite establecer el rango.

+0

relacionada, puede ser útil: http://stackoverflow.com/questions/2290057/how -to-generate-a-random-biginteger-value-in-java –

+1

¿Ha considerado obtener su larga aleatoria y tomar el mod de su rango? (Por supuesto, si el rango es solo 100 produciría un int random y lo lanzaría a long.) –

+0

'java.util.Random' solo usa una distribución de 48 bits (ver detalles de implementación), por lo que no tendrá una distribución normal. –

Respuesta

108

A partir de Java 7 (o Android API de nivel 21 = 5.0 o superior) se puede utilizar directamente ThreadLocalRandom.current().nextLong(n) (para 0 ≤ x < n) y ThreadLocalRandom.current().nextLong(m, n) (para m ≤ x < n). Ver la respuesta de @Alex para más detalles.


Si le pegan con Java 6 (o Android 4.x) es necesario utilizar una biblioteca externa (por ejemplo org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1), ver @mawaldne 's respuesta), o poner en práctica su propio nextLong(n).

Según http://java.sun.com/j2se/1.5.0/docs/api/java/util/Random.htmlnextInt se implementa como

public int nextInt(int n) { 
    if (n<=0) 
       throw new IllegalArgumentException("n must be positive"); 

    if ((n & -n) == n) // i.e., n is a power of 2 
     return (int)((n * (long)next(31)) >> 31); 

    int bits, val; 
    do { 
     bits = next(31); 
     val = bits % n; 
    } while(bits - val + (n-1) < 0); 
    return val; 
} 

Así podremos modificar este para realizar nextLong:

long nextLong(Random rng, long n) { 
    // error checking and 2^x checking removed for simplicity. 
    long bits, val; 
    do { 
     bits = (rng.nextLong() << 1) >>> 1; 
     val = bits % n; 
    } while (bits-val+(n-1) < 0L); 
    return val; 
} 
+1

Tengo algunos problemas con la parte "2^x checking". ¿Algunas ideas? –

+0

@Vilius: la comprobación 2^x solo hace que la generación sea más rápida porque al usar directamente 'rng.nextLong()% n' se obtendrán valores uniformes (suponiendo que todos los bits son buenos). Puede ignorar esa parte si lo desea. – kennytm

+0

Si quiero 'm <= x <= n', ¿cómo modificaría su solución? –

70

El método estándar para generar un número (sin un método de utilidad) en un intervalo es usar sólo el doble con la gama:

long range = 1234567L; 
Random r = new Random() 
long number = (long)(r.nextDouble()*range); 

le dará un largo entre 0 (inclusive) y el rango (exclusivo). Del mismo modo, si usted quiere un número entre X e Y:

long x = 1234567L; 
long y = 23456789L; 
Random r = new Random() 
long number = x+((long)(r.nextDouble()*(y-x))); 

le dará mucho de 1234567 (inclusive) hasta 123456789 (exclusivo)

Nota: comprobar paréntesis, porque la fundición a largo tiene mayor prioridad que multiplicación.

+4

Mi primera idea fue exactamente esto. Pero parece ser un poco poco elegante. Y me preocupa la uniformidad de la distribución (no es que realmente lo necesite, solo quiero hacerlo bien) –

+3

Por favor nunca use esto. La salida no es uniforme en absoluto. – Navin

+0

El mayor problema es que el redondeo hará que el bit más bajo no sea uniforme. Además, 'bound' tendrá que ser menor que el entero más grande que pueda codificarse en un doble, 2^53. –

1

Desde la página en Random:

El método nextLong es implementado por clase Aleatorio como por:

public long nextLong() { 
    return ((long)next(32) << 32) + next(32); 
} 

Como la clase Random usa una semilla con solo 48 bits, este algoritmo no devolverá todos los valores largos posibles.

Así que si quieres obtener un Long, ya no obtendrás el rango completo de 64 bits.

sugeriría que si usted tiene un rango que cae cerca de una potencia de 2, que construir la Long como en el fragmento, así:

next(32) + ((long)nextInt(8) << 3) 

para obtener un rango de 35 bits, por ejemplo, .

+2

Pero la documentación dice "Todos los 2^64 valores posibles largos se producen con (aproximadamente) la misma probabilidad". Aparentemente, el método nextLong() debería devolver todos los valores posibles. Por cierto, ¿cómo la longitud de la semilla está relacionada con la distribución de valores? –

2

Muchas gracias por esta publicación. Es justo lo que necesitaba. Tuve que cambiar algo para obtener la parte que solía trabajar.

que tiene la siguiente (incluido arriba):

long number = x+((long)r.nextDouble()*(y-x)); 

para trabajar cambiándola a:

long number = x+ (long)(r.nextDouble()*(y-x)); 

desde (long)r.nextDouble() es siempre cero.

+0

Lanzar a largo tiene una prioridad mayor que la multiplicación. – Stephan

+0

Por favor nunca use esto. La salida no es uniforme en absoluto. – Navin

+1

Este es un comentario de una respuesta existente, no una respuesta. –

0

Los métodos que utilizan la r.nextDouble() deben utilizar:

long number = (long) (rand.nextDouble()*max); 


long number = x+(((long)r.nextDouble())*(y-x)); 
12

los métodos anteriores trabajos grandes. Si está utilizando apache commons (org.apache.commons.math.random), consulte RandomData. Tiene un método: nextLong (inferior larga, larga superior)

http://commons.apache.org/math/userguide/random.html

http://commons.apache.org/math/api-1.1/org/apache/commons/math/random/RandomData.html#nextLong(long,%20long)

+3

Para la posteridad: RandomData está en desuso en 4.0. Use http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/random/RandomDataGenerator.html –

10

Utilice el '%' operador

resultingNumber = (r.nextLong() % (maximum - minimum)) + minimum; 

Al utilizar el operador '%', tomamos el resto cuando se divide por su valor máximo. Esto nos deja con solo números desde 0 (inclusive) hasta el divisor (exclusivo).

Por ejemplo: tiempo

public long randLong(long min, long max) { 
    return (new java.util.Random().nextLong() % (max - min)) + min; 
} 
+0

Esto es bueno, pero debe verificar 'if (max == min)' – Aigori

+0

Y también marque 'if (nextLong()> = 0)' – Aigori

+5

FYI: Esto no siempre da una distribución uniforme, y es realmente malo para algunos rangos grandes. Por ejemplo, si 'min = 0' y' max = 2 * (MAX_LONG/3) ', entonces tiene el doble de posibilidades de obtener un valor en' [0, MAX_LONG/3] 'que usted para obtener uno '[MAX_LONG/3, 2 * (MAX_LONG/3)]'. – Nick

-3

// sistema uso como valor de inicialización para conseguir un buen número aleatorio

Random random = new Random(System.currentTimeMillis()); 
       long x; 
      do{ 
       x=random.nextLong(); 
      }while(x<0 && x > n); 

// Loop hasta obtener un número mayor o igual que 0 y menor que n

+0

Esto puede ser extremadamente ineficiente. ¿Qué pasa si 'n' es 1, o decir 2? El ciclo realizará __many__ iteraciones. – Magnilex

48

ThreadLocalRandom

ThreadLocalRandom tiene un nextLong(long bound) método.

long v = ThreadLocalRandom.current().nextLong(100); 

También tiene nextLong(long origin, long bound) si necesita un origen distinto de 0. Pase el origen (ambos inclusive) y el límite (exclusivo).

long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive. 

SplittableRandom tiene los mismos métodos nextLong y le permite elegir una semilla si quieres una secuencia de números reproducibles.

+3

Esta respuesta es mucho más simple y, por lo tanto, más útil que la más votada. – yurin

+1

Para los desarrolladores de Android, fíjate que solo está disponible en API 21 (Lollipop, Android 5.0): http://developer.android.com/reference/java/util/concurrent/ThreadLocalRandom.html –

+1

Esta debería ser la respuesta aceptada . –

1

Seguir mejorando la respuesta de kennytm: Una aplicación subclase tomando la implementación real en Java 8 en cuenta serían:

public class MyRandom extends Random { 
    public long nextLong(long bound) { 
    if (bound <= 0) { 
     throw new IllegalArgumentException("bound must be positive"); 
    } 

    long r = nextLong() & Long.MAX_VALUE; 
    long m = bound - 1L; 
    if ((bound & m) == 0) { // i.e., bound is a power of 2 
     r = (bound * r) >> (Long.SIZE - 1); 
    } else { 
     for (long u = r; u - (r = u % bound) + m < 0L; u = nextLong() & Long.MAX_VALUE); 
    } 
    return r; 
    } 
} 
1

¿Qué tal esto:

public static long nextLong(@NonNull Random r, long min, long max) { 
    if (min > max) 
     throw new IllegalArgumentException("min>max"); 
    if (min == max) 
     return min; 
    long n = r.nextLong(); 
    //abs (use instead of Math.abs, which might return min value) : 
    n = n == Long.MIN_VALUE ? 0 : n < 0 ? -n : n; 
    //limit to range: 
    n = n % (max - min); 
    return min + n; 
} 

?

0
public static long randomLong(long min, long max) 
{ 
    try 
    { 
     Random random = new Random(); 
     long result = min + (long) (random.nextDouble() * (max - min)); 
     return result; 
    } 
    catch (Throwable t) {t.printStackTrace();} 
    return 0L; 
} 
+0

No debe crear instancias 'Random' en hoc, no debe capturar' Throwable's u otras excepciones si no es necesario, debe registrar errores con algún tipo de estructura de registro (es decir, SLF4J) en lugar de usar 'printStackTrace'. –

1

Si desea un pseudoaleatorio uniformemente distribuida larga en la gama de [0, m), intente utilizar el operador de módulo y el método de valor absoluto en combinación con el método de nextLong() como se ve a continuación:

Math.abs(rand.nextLong()) % m; 

Donde rand es su objeto Aleatorio.

El operador de módulo divide dos números y emite el resto de esos números. Por ejemplo, 3 % 2 es 1 porque el resto de 3 y 2 es 1.

Desde nextLong() genera una pseudoaleatorio uniformemente distribuida largo en el intervalo de [- (2^48), 2^48) (o en algún lugar en ese rango), tendrá que tomar el valor absoluto de la misma. Si no lo hace, el módulo del método nextLong() tiene un 50% de probabilidad de devolver un valor negativo, que está fuera del rango [0, m).

Lo que solicitó inicialmente fue una secuencia pseudoaleatoria uniformemente distribuida en el rango de [0,100). El siguiente código hace:

Math.abs(rand.nextLong()) % 100; 
0

El Método continuación se devolverá un valor entre 10000000000 a 9999999999

long min = 1000000000L 
long max = 9999999999L  

public static long getRandomNumber(long min, long max){ 

    Random random = new Random();   
    return random.nextLong() % (max - min) + max; 

} 
+0

Cuando restablezco \t \t long min = 1L; long max = 10L; ¡El número aleatorio resultante va más allá del valor máximo! –

Cuestiones relacionadas