2010-12-25 28 views
16

Tôi hơi bối rối, cách thực hiện việc này. Tôi biết tôi có thể sử dụng lớp ngẫu nhiên để tạo ra các số ngẫu nhiên, nhưng tôi không biết làm thế nào để xác định và tạo ra số 8-byte?Tạo số 8 byte trong Java

Cảm ơn, Vuk

Trả lời

13

Bạn nên lưu ý rằng lớp java.util.Random sử dụng một hạt giống 48-bit, vì vậy không phải tất cả các giá trị 8-byte (chuỗi 64 bit) có thể được tạo ra sử dụng lớp này . Do hạn chế này, tôi khuyên bạn nên sử dụng SecureRandomnextBytes method trong trường hợp này.

Cách sử dụng khá giống với giải pháp java.util.Random.

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

Đây là lý do tại sao một hạt giống 48-bit là không đủ:

  • Lớp Random thực hiện một giả phát ngẫu nhiên có nghĩa là nó là xác định.
  • "trạng thái" hiện tại của Random xác định chuỗi bit trong tương lai.
  • Vì nó có 2 tuyên bố, không thể có nhiều hơn 2 các chuỗi tương lai có thể có.
  • Vì giá trị 8 byte có 2 các khả năng khác nhau, một số khả năng này sẽ không bao giờ được đọc từ đối tượng Random.

Dựa trên @Peter Lawreys excellent answer (nó xứng đáng hơn upvotes!): Đây là một giải pháp cho việc tạo ra một java.util.Random với 2 × hạt giống 48-bit. Tức là, một cá thể java.util.Random có khả năng tạo ra tất cả có thể 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

nó không phải là mát mẻ để lại cùng một bình luận dưới mỗi câu trả lời duy nhất. – Roman

+2

Tại sao không? Tôi nghĩ không sao. Nó áp dụng cho mỗi câu trả lời tôi nhận xét. – aioobe

+0

Giải pháp trực quan của tôi là tạo ra hai giá trị 4 byte. Nếu tôi hiểu bạn một cách chính xác thì điều này sẽ không hiệu quả vì hai giá trị đó sẽ bị loại trừ (hoặc ít nhất là không có khả năng) bằng nhau khi sử dụng cùng một Generator hai lần. Ví dụ. FF FF sẽ không có khả năng như FF AA? Tôi không biết PRG được triển khai như thế nào, điều này khiến tôi ngạc nhiên vì tôi mong đợi mỗi con số sẽ độc lập với số trước đó. – zockman

5

Nó có thể được thực hiện hoặc với mảng byte có độ dài 8:

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

hoặc với một biến kiểu long (đại diện cho số 8-byte):

long randomLong = random.nextLong(); 
+2

Lưu ý rằng cả hai phương án này đều không thể tạo ra tất cả giá trị 8 byte có thể có. Xem câu trả lời của tôi. – aioobe

+0

@aioobe: bạn có thể giải thích tại sao không? Tôi đã đọc tài liệu và tôi đã đọc phần triển khai và tôi vẫn chưa hiểu rõ. Có khá phức tạp (toán học dựa trên) thuật toán, và như tôi hiểu, nó tạo ra các giá trị phụ thuộc. Và nếu đó là sự thật, thì một ví dụ ngẫu nhiên không thực sự tạo ra tất cả các giá trị có thể có của thời gian dài. Nhưng khác nhau 'Random's (với khác nhau" điểm bắt đầu ") làm. Tôi có đúng không? – Roman

+0

Đã cập nhật câu trả lời của tôi. – aioobe

0

Một chút điều chỉnh từ mã 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); 
    } 
} 

Một số đọc thêm: Math.random() versus Random.nextInt(int)

+0

Lưu ý rằng lớp 'Random' không có khả năng tạo ra tất cả các giá trị 8 byte có thể có. – aioobe

2

Loại long là 8 byte ký số nguyên, vì vậy Random.nextLong() dường như để làm những gì bạn muốn. Hoặc nếu bạn cần một mảng byte kết quả:

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

Lưu ý rằng lớp 'Random' không có khả năng tạo ra tất cả thời gian có thể. – aioobe

11

Tôi đồng ý với @aioobe 'điểm về Ngẫu nhiên sử dụng hạt giống 48 bit. SecureRandom là một giải pháp tốt hơn. Tuy nhiên để trả lời các câu hỏi của OP về cách sử dụng lớp Random và vẫn cho phép tất cả các giá trị 8 byte có thể là thiết lập lại hạt giống định kỳ.

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; 

Chỉ ngẫu nhiên cho phép chuỗi có giá trị dài 2^47. Bằng cách sử dụng hai máy phát ngẫu nhiên, một trong số đó tiếp tục nhảy xung quanh theo trình tự, bạn nhận được hai giá trị có thể là 2^47 * 2^47. Việc sử dụng < < 1 là để tránh tác động của việc có cả hai hạt giống có cùng hạt giống (trong trường hợp này sẽ tạo ra 0 cho 4 tỷ giá trị liên tiếp)

+0

+1, Câu trả lời hay. Thú vị ghi chú về việc thiết lập lại và thay đổi-trái! Tôi muốn câu trả lời thậm chí còn tốt hơn nếu bạn đóng gói các thể hiện ngẫu nhiên trong một phân lớp đồng nghĩa của Random. – aioobe

+0

Sẽ không hai đối tượng ngẫu nhiên tạo chính xác các số ngẫu nhiên giống nhau vì cả hai sẽ có cùng một hạt giống? (tức là trên một máy tính nhanh System.currentTimeMillis() sẽ giống nhau cho cả hai?) –

+0

Trên các phiên bản Java cũ là đúng. Từ Java 5.0, Random sử dụng System.nanoTime() và bộ đếm AtomicLong. –