2011-04-29 49 views
23

Tengo problemas con Javas Random clase, si hago esto:Java aleatoria dando números negativos

Random rng = new Random(seed) // seed == 29 in this example 

String ss = ""; 
     for(int i = 0; i < 10; i++) 
     { 
      int s = rng.nextInt(); 
      ss += Integer.toString(s); 
      ss +="\n"; 
     } 

Esto es lo que me sale de vuelta:

-1169335537 
-2076183625 
1478047223 
1914482305 
722089687 
2094672350 
-1234724057 
-1614953544 
-321574001 
1000360613 

Por lo que he leído este solo debería devolver números positivos para empezar?

Esto puede ser un poco exagerado, pero no podría tener nada que ver con la ejecución de una máquina de 64 bits en Windows 7 de 64 bits?

¡Cualquier ayuda en absoluto sería increíble si necesita terminar esto para una tarea de asignación hoy!

+0

solo cree lo que lee en los javadocs. Y (por supuesto) ** lea los javadocs **. –

+3

Nota 'Math.abs' no funcionará una sola vez en 2 . (Y buena suerte probar eso. Sugerencia: No use un objeto mutable estático.) –

Respuesta

46

Desde el Java docs for nextInt():

Todos 2 posibles valores int se producen con (aproximadamente) igual probabilidad.

Un método consiste en utilizar el siguiente transformar:

s = rng.nextInt() & Integer.MAX_VALUE; // zero out the sign bit 

La razón algo como esto que se necesita (en lugar de utilizar el valor absoluto o negación) es que Integer.MIN_VALUE es demasiado grande en valor absoluto para ser convertido en un entero positivo. Es decir, debido al desbordamiento, Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE y Integer.MIN_VALUE == -Integer.MIN_VALUE. La transformación anterior conserva la propiedad de distribución aproximadamente uniforme: si escribió un ciclo de generar y probar que simplemente arrojó Integer.MIN_VALUE y devolvió el valor absoluto de todo lo demás, entonces los enteros positivos tendrían el doble de probabilidad que cero. Al asignar Integer.MIN_VALUE a cero, eso hace que la probabilidad de cero esté en línea con los enteros positivos.

Aquí es otro enfoque, que puede ser en realidad un poquito más rápido (aunque no he referenciado IT):

int s = rng.next(Integer.SIZE - 1); // Integer.SIZE == 32 

Esto generará un número entero con 31 bits de orden al azar (y 0 como el 32 nd bit, garantizando un valor no negativo). Sin embargo (como se señala en el comentario de jjb), ya que es un método next(int)protected de Random, que tendrá que subclase Random para exponer el método (o para proporcionar un sustituto adecuado para el método):

public class MyRandom extends Random { 
    public MyRandom() {} 
    public MyRandom(int seed) { super(seed); } 

    public int nextNonNegative() { 
     return next(Integer.SIZE - 1); 
    } 
} 

Otro enfoque es usar un ByteBuffer que envuelve una matriz de 4 bytes. A continuación, puede generar cuatro bytes aleatorios (llamando al nextBytes(byte[])), poner a cero el bit de signo y luego leer el valor como int. No creo que esto ofrezca ninguna ventaja sobre lo anterior, pero pensé que simplemente lo lanzaría allí. Es básicamente lo mismo que mi primera solución (que enmascara con Integer.MAX_VALUE).

En una versión anterior de esta respuesta, me sugirió usando:

int s = rng.nextInt(Integer.MAX_VALUE); 

Sin embargo, de acuerdo con the docs Esto generará números enteros en el rango de 0 (incluido) a Integer.MAX_VALUE (exclusivo). En otras palabras, no generará el valor Integer.MAX_VALUE. Además, resulta que next(int) siempre será más rápido que nextInt(int).

+1

Random.next() está protegido, por lo que no puede llamarlo directamente. Puede subclase Aleatorio y exponer algo como nextPositiveInt() que devuelve next (31) con bastante facilidad. – jjb

+0

@jjb - Buen punto. Actualizaré la respuesta para aclarar. –

+1

'Integer.SIZE - 1' sería un poco más agradable. –

8

Se permiten números negativos: tal vez haya leído del método aleatorio similar nextInt(int) que hace limitando los valores devueltos a cero o mayor.

+0

Tal como lo menciona Ted, 'nextInt (Integer.MAXVALUE)' omite 'Integer.MAXVALUE', por lo que es algo tan bueno como lo obvio 'Math.abs' que obtiene un valor incorrecto (' Integer.MAXVALUE'). –

0

Per la documentación http://download.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt():

devuelve el siguiente pseudoaleatorio, uniformemente distribuida valor int partir de la secuencia de este generador de números aleatorios. El contrato general de nextInt es que un valor int se genera y se devuelve pseudoaleatoriamente. Todos los 2^32 valores int posibles se producen con (aproximadamente) la misma probabilidad.

Sólo multiplicar por -1 si el valor es negativo

+2

Multiplicar por -1 no es una buena idea. Primero, no funciona: la negación de 'Integer.MIN_VALUE' es' Integer.MIN_VALUE' nuevamente (debido a un desbordamiento), por lo que no puede deshacerse de todos los números negativos de esa manera. Incluso si funcionara, el resultado sería una distribución no uniforme: cero tendría la mitad de la probabilidad de cualquier entero positivo. –

0
int s = rng.nextInt(seed); //seed 29 in this case 

Esto tendrá un límite de a .

+0

¡Perfecto! ¡No estoy seguro de por qué esto fue votado! – smac89

7

Puesto que hay una oportunidad igual de números positivos o negativos por qué no sólo:

Math.abs(rand.nextInt()) 

agradable y fácil!

+5

Esto no funcionará. De [docs for 'Math.abs (int)'] (https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-int-): "Tenga en cuenta que si el argumento es igual al valor de 'Integer.MIN_VALUE', el valor' int' representable más negativo, el resultado es el mismo valor, que es negativo. " –

+14

Entonces deberían haber llamado al método Math.absExceptIfTheArgumentIsEqualToIntegerMinValueInWhichCaseGoodBloodyLuckToYou (int); – kaifong

0

Si trabaja con números que tienen la posibilidad de tener un valor negativo, puede convertirlo en un valor positivo usando una declaración condicional automáticamente al multiplicar el valor por uno negativo. También puede convertir un valor positivo en negativo usando este mismo método.

Los ejemplos están a continuación.

// Turn a negative value into its positive correspondent value. 
// If the value is already a positive value, nothing will happen to it. 
int a = -5; 
a = a < 0? a * -1 : a; 

// Turn a positive value into its negative correspondent value. 
// If the value is already a negative value, nothing will happen to it. 
int b = 5; 
b = b > 0? b * -1 : b; 
+0

Desafortunadamente, esto no funciona para 'Integer.MIN_VALUE' porque' Integer.MIN_VALUE == -Integer.MIN_VALUE' debido a un desbordamiento. –

+0

Para solucionar el problema del valor mínimo entero o el problema del valor máximo, si no le importa que el número sea un número desactivado, puede hacerlo, b = b <0? b == Integer.MIN_VALUE? (b + 1) * -1: b * -1: b; –

+0

Si necesita el número para ser preciso, necesita una segunda línea para corregir correctamente el problema de desbordamiento. La solución anterior es solo para cuando trabajas con un número aleatorio y no te importa si el número puede ser un dígito diferente. –

Cuestiones relacionadas