2011-01-27 50 views
7

thể trùng lặp:
Why does this Random Number Generator not random?Tại sao không ngẫu nhiên() ngẫu nhiên?

tôi có chương trình thử nghiệm này:

static void Main(string[] args) 
{ 
    var randomNumbers = new Dictionary<int, int>(); 
    foreach (var s in Enumerable.Range(1, 500)) 
    { 
     var rand = Rand5(); 
     if (!randomNumbers.ContainsKey(rand)) 
      randomNumbers.Add(rand, 1); 
     else 
      randomNumbers[rand] += 1; 
    } 

    randomNumbers 
     .ToList() 
     .ForEach(x => Console.WriteLine("{0}: {1}", x.Key, x.Value)); 
    Console.ReadLine(); 
} 

static int Rand5() 
{ 
    System.Threading.Thread.Sleep(1); 
    return new Random().Next(1, 6); 
} 



Nếu tôi nhận xét ra System.Threading.Thread.Sleep(1);, tôi nhận được

5: 500 

Nhưng nếu tôi bỏ ghi chú dòng đó, tôi sẽ nhận được số ngẫu nhiên.

2: 87 
4: 94 
1: 116 
5: 108 
3: 95 

Tại sao dòng mã lại quan trọng? Cảm ơn!

+0

Tôi đoán việc vô ích khi đánh dấu các câu hỏi như vậy là do có lẽ khoảng một phần ba trong số tất cả các câu hỏi * ngẫu nhiên - được gắn thẻ là cùng một vấn đề .. – Joey

Trả lời

10

Như những người khác đã nói, new Random() hạt các bộ tạo số ngẫu nhiên từ thời gian hệ thống hiện hành.

Tôi có an article mô tả chi tiết hơn, bao gồm các giải pháp cho vấn đề mà bạn có thể thấy hữu ích. Về cơ bản, bạn muốn sử dụng cùng một phiên bản Random nhiều lần - nhưng quan sát rằng nó là không phải là an toàn chỉ.

+0

Cảm ơn câu trả lời với giải thích chi tiết. Bằng cách này, tôi đang đọc C# của bạn trong chiều sâu 2 :) – bla

+0

Wow, đó là một bài viết tuyệt vời. Tôi hiểu vấn đề này tốt hơn tôi đã làm 10 phút trước. –

+0

Đây là lý do tại sao tôi muốn 'System.Random' là một singleton tĩnh, được tạo ra một cách lười biếng. –

3

Nguyên nhân nó bằng cách sử dụng đồng hồ như một hạt giống để tạo ra số và khi bạn tạo số ngẫu nhiên theo cách đó, bạn sẽ có được những con số cùng

2

Các bộ tạo số ngẫu nhiên dựa một phần trên đồng hồ hệ thống, và C# là quá darn nhanh chóng đuổi chúng ra ...

11

Loại Random được gieo mặc định theo thời gian hệ thống hiện tại, có độ chi tiết hữu hạn.

Gọi số new Random().Next(1, 6) nhiều lần trong kế tiếp nhanh chóng do đó sẽ xây dựng nhiều đối tượng có cùng giá trị hạt giống, tạo ra cùng một kết quả. Các cuộc gọi Thread.Sleep(1) "giải quyết" vấn đề này bằng cách chỉ đơn giản là khoảng cách các cấu trúc xa nhau trong thời gian, tăng xác suất của các giá trị hạt giống riêng biệt.

Bạn cần phải giữ một đối tượng cụ thể Random từ một cuộc gọi đến tiếp theo:

var randomNumbers = new Dictionary<int, int>(); 
var random = new Random(); // Re-use this, don't keep creating new ones. 
foreach (var s in Enumerable.Range(1, 500)) 
{ 
    var rand = random.Next(1, 6); 
    // ... 
1

Nếu bạn không gieo rắc sự ngẫu nhiên, bạn nhận được số giống như ngẫu nhiên là một pseudo-random-máy phát điện

Bằng cách sử dụng Thread.Sleep (1) bạn cho phép bộ đếm thời gian để thăng tiến và để tạo ra một mới hạt giống tự sinh.

Cách để "sửa" là tạo 1 đối tượng ngẫu nhiên và sử dụng lại nó (như một số khác cũng trả lời) hoặc sử dụng trình tạo ngẫu nhiên khác. Thông tin

Thông tin thêm về http://msdn.microsoft.com/en-us/library/ctssatww.aspx

0

Bất kỳ bộ tạo số ngẫu nhiên bạn sử dụng là một số giả ngẫu nhiên. Điều này sẽ luôn có giá trị hạt giống được xác định trước và tốt cho thử nghiệm nhưng không phải để thực hiện các tính năng ngẫu nhiên thực sự.

Bạn nên sử dụng chuỗi số ngẫu nhiên để tạo các số ngẫu nhiên hoặc tốt hơn, chuỗi Markovs để tạo các số ngẫu nhiên tốt nhất. Nếu bạn có kế hoạch sử dụng một trong những chức năng Ngẫu nhiên, bạn sẽ không phải bất cứ điều gì gần với sự ngẫu nhiên thực sự.