2010-12-25 45 views
16

Estoy un poco confundido, cómo hacerlo. Sé que puedo usar la clase Random para generar números aleatorios, pero no sé cómo especificar y generar un número de 8 bytes.Generar un número de 8 bytes en Java

Gracias, Vuk

Respuesta

13

Debe tener en cuenta que la clase java.util.Random utiliza una semilla de 48 bits, por lo que no todos los valores de 8 bytes (secuencias de 64 bits) se pueden generar utilizando esta clase . Debido a esta restricción, le sugiero que use SecureRandom y nextBytes method en esta situación.

El uso es bastante similar a la solución java.util.Random.

SecureRandom sr = new SecureRandom(); 
byte[] rndBytes = new byte[8]; 
sr.nextBytes(rndBytes); 

Aquí es la razón por la cual una semilla de 48 bits no es suficiente:

  • La clase Random implementa un generador pseudo-aleatorio que significa que es determinista.
  • El "estado" actual de Random determina la secuencia futura de bits.
  • Dado que tiene 2 estados, no puede tener más de 2 posibles secuencias futuras.
  • Dado que un valor de 8 bytes tiene 2 diferentes posibilidades, algunas de estas posibilidades nunca se leerán desde el objeto Random.

Basado en @Peter Lawreys excellent answer (que merece más upvotes!): Aquí se presenta una solución para la creación de un × semilla de 48 bits con 2 java.util.Random. Es decir, una instancia java.util.Random capaz de generar todas las posibles long s.

class Random96 extends Random { 
    int count = 0; 
    ExposedRandom extra48bits; 

    class ExposedRandom extends Random { 
     public int next(int bits) { // Expose the next-method. 
      return super.next(bits); 
     } 
    } 

    @Override 
    protected int next(int bits) { 
     if (count++ == 0) 
      extra48bits = new ExposedRandom(); 
     return super.next(bits)^extra48bits.next(bits) << 1; 
    } 
} 
+0

no es bueno dejar el mismo comentario en cada respuesta. – Roman

+2

¿Por qué no? Creo que está bien. Se aplica a cada respuesta que comenté. – aioobe

+0

Mi solución intuitiva habría sido generar dos valores de 4 bytes. Si te entiendo correctamente, esto no funcionaría porque los dos valores se excluirían (o al menos no sería probable) de ser igual cuando se usa el mismo generador dos veces. P.ej. ¿FF FF no sería tan probable como FF AA? No sé cómo se implementan los PRG, así que esto me sorprendió ya que esperaría que cada número fuera (pseudo-) independiente de los números anteriores. – zockman

5

Se puede hacer ya sea con matriz de bytes de longitud 8:

byte[] byteArray = new byte[8];  
random.nextBytes(byteArray); 

o con una variable de tipo long (que representa números de 8 bytes):

long randomLong = random.nextLong(); 
+2

Tenga en cuenta que ninguna de estas dos alternativas es capaz de generar todo valores posibles de 8 bytes. Ver mi respuesta – aioobe

+0

@aioobe: ¿puedes explicar por qué? He leído los documentos y he leído la implementación y todavía no entiendo bien. Existe un algoritmo bastante complejo (basado en matemática), y según tengo entendido, genera valores dependientes. Y si es verdad, entonces una instancia aleatoria realmente no genera todos los valores posibles de longs. Pero diferentes 'Aleatorios' (con diferentes" puntos de inicio ") sí lo hacen. ¿Estoy en lo cierto? – Roman

+0

Actualizado mi respuesta. – aioobe

0

Un poco de ajuste desde el código here:

import java.util.Random; 

/** Generate 10 random integers in the range 0..99. */ 
public final class RandomByte { 

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

    //note a single Random object is reused here 
    Random randomGenerator = new Random(); 
    for (int idx = 1; idx <= 10; ++idx){ 
     int randomInt = randomGenerator.nextInt(256); 
     // int randomInt = randomGenerator.nextBytes(256); 
     log("Generated : " + randomInt); 
    } 

    log("Done."); 
    } 

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

leer un poco más lejos: Math.random() versus Random.nextInt(int)

+0

Tenga en cuenta que la clase 'Random' es incapaz de generar todos los valores posibles de 8 bytes. – aioobe

2

El tipo long es un entero de 8 bytes, por lo Random.nextLong() parece hacer lo que quiera. O si necesita una matriz de bytes como resultado:

byte[] result = new byte[8]; 
Random.nextBytes(result); 
+1

Tenga en cuenta que la clase 'Random' es incapaz de generar todas las longitudes posibles. – aioobe

11

Estoy de acuerdo con @aioobe 'punto acerca de Random con una semilla de 48 bits. SecureRandom es una mejor solución. Sin embargo, para responder a las preguntas del OP sobre cómo usar la clase Random y aun así permitir todos los posibles valores de 8 bytes, se debe restablecer el seed periódicamente.

int counter = 0; 
Random rand = new Random(); 
Random rand2 = new Random(); 

if (++counter == 0) rand = new Random(); // reset every 4 billion values. 

long randomLong = rand.nextLong()^rand2.nextLong() << 1; 

Al azar solo permite una secuencia de 2^47 valores largos. Al usar dos generadores aleatorios, uno que sigue dando saltos en la secuencia, obtienes dos 2^47 * 2^47 valores posibles. El uso de < < 1 es para evitar el impacto de tener ambos randoms con la misma semilla (en cuyo caso^produciría 0 para 4 mil millones de valores en una fila)

+0

+1, Gran respuesta. Notas interesantes sobre el reinicio y el cambio a la izquierda Me gustaría que la respuesta sea aún mejor si encapsulaste la instancia Aleatoria en una subclase anónima de Aleatorio. – aioobe

+0

¿No crearán los dos objetos aleatorios exactamente los mismos números aleatorios ya que ambos tendrán la misma semilla? (es decir, en una computadora veloz System.currentTimeMillis() será la misma para ambos?) –

+0

En las versiones anteriores de Java, eso es cierto. Desde Java 5.0, Random usa System.nanoTime() y un contador AtomicLong. –

Cuestiones relacionadas