2010-12-25 15 views
16

Jestem trochę zmieszany, jak to zrobić. Wiem, że mogę używać losowej klasy do generowania liczb losowych, ale nie wiem jak określić i wygenerować 8-bajtową liczbę?Generowanie 8-bajtowego numeru w Javie

dzięki, Vuk

Odpowiedz

13

Należy pamiętać, że klasa java.util.Random wykorzystuje ziarno 48-bitowe, więc nie wszystkie wartości 8-bajtowych (sekwencje 64 bitów) mogą być generowane przy użyciu tej klasy . Z powodu tego ograniczenia sugeruję użycie SecureRandom i nextBytes method w tej sytuacji.

Użycie jest podobne do rozwiązania java.util.Random.

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

tutaj Dlatego ziarno 48-bitowe nie wystarcza:

  • Klasa Random realizuje pseudo losowy generator, który oznacza, że ​​jest deterministyczny.
  • Aktualny "stan" Random określa przyszłą sekwencję bitów.
  • Ponieważ ma 2 stwierdza, że ​​nie może mieć więcej niż 2 możliwych przyszłych sekwencji.
  • Ponieważ 8-bajtowa wartość ma 2 różnych możliwości, niektóre z tych możliwości nigdy nie zostaną odczytane z obiektu Random.

podstawie @Peter Lawreys excellent answer (to zasługuje na upvotes!) Oto rozwiązanie tworzenia java.util.Random z 2 × 48-bitowy nasion. To znaczy, instancja java.util.Random zdolna do generowania wszystkich możliwych 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

nie jest fajnie zostawić ten sam komentarz pod każdą odpowiedzią. – Roman

+2

Dlaczego nie? Myślę, że to w porządku. Dotyczy to każdej odpowiedzi, którą skomentowałem. – aioobe

+0

Moje intuicyjne rozwiązanie polegałoby na wygenerowaniu dwóch wartości 4-bajtowych. Jeśli rozumiem cię poprawnie, to nie zadziałałoby, ponieważ dwie wartości byłyby wykluczone (lub przynajmniej mało prawdopodobne) z równości przy dwukrotnym użyciu tego samego Generatora. Na przykład. FF FF nie byłby tak prawdopodobny jak FF AA? Nie wiem, w jaki sposób realizowane są PRG, więc zaskoczyło mnie to, ponieważ oczekiwałbym, że każda liczba będzie (pseudo-) niezależna od poprzednich liczb. – zockman

5

Może to być wykonane albo z tablicy bajtów długości 8:

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

lub zmiennej typu long (co oznacza liczby 8-bajtowych)

long randomLong = random.nextLong(); 
+2

Należy zauważyć, że żadna z tych dwóch metod nie jest w stanie wygenerować wszystkich możliwe wartości 8 bajtów. Zobacz moją odpowiedź. – aioobe

+0

@aioobe: możesz wyjaśnić, dlaczego? Czytałem dokumenty i przeczytałem implementację i nadal nie mam jasnego zrozumienia. Jest dość złożony (oparty na matematyce) algorytm i jak rozumiem, generuje wartości zależne. A jeśli to prawda, to jedna przypadkowa instancja nie generuje wszystkich możliwych wartości długich. Ale różne "losowe" (z różnymi "punktami początkowymi") mają. Czy mam rację? – Roman

+0

Zaktualizowałem moją odpowiedź. – aioobe

0

Trochę regulacji z kodem 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); 
    } 
} 

Niektóre dalsze czytanie: Math.random() versus Random.nextInt(int)

+0

Należy zauważyć, że klasa 'Random' nie jest w stanie wygenerować wszystkich możliwych 8-bajtowych wartości. – aioobe

2

Typ long jest 8 bajtów podpisane całkowitą, więc Random.nextLong() wydaje się robić to, co chcesz. Lub jeśli trzeba tablicę bajtów w wyniku:

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

Należy zauważyć, że klasa 'Random' nie jest w stanie wygenerować wszystkich możliwych longów. – aioobe

11

Zgadzam się z punktem @aioobe o losowym użyciu 48-bitowego materiału siewnego. SecureRandom to lepsze rozwiązanie. Jednak aby odpowiedzieć na pytania OP, w jaki sposób korzystać z klasy Losowe i nadal pozwalać na wszystkie możliwe 8-bajtowe wartości, należy okresowo resetować nasiona.

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; 

Tylko losowo pozwala na sekwencję 2^47 długich wartości. Używając dwóch generatorów losowych, które ciągle przeskakują w sekwencji, otrzymujesz dwie 2^47 * 2^47 możliwych wartości. Użycie funkcji < < 1 polega na uniknięciu wpływu, jaki ma posiadanie obu wysięgników na to samo nasienie (w tym przypadku^powodowałoby 0 dla 4 miliardów wartości z rzędu).

+0

+1, Świetna odpowiedź. Interesujące notatki dotyczące resetowania i przesunięcia w lewo! Chciałbym, aby odpowiedź była jeszcze lepsza, jeśli obudowałeś przypadek losowy w annonymous subclass of Random. – aioobe

+0

Czy dwa obiekty losowe nie utworzą identycznych liczb losowych, ponieważ oba te elementy będą miały to samo ziarno? (na szybkim komputerze System.currentTimeMillis() będzie taki sam dla obu?) –

+0

W starych wersjach Javy jest to prawda. Z wersji Java 5.0 Random używa System.nanoTime() i licznika AtomicLong. –