2011-03-10 133 views
17

考虑这个方法:为什么Random.Next()总是返回相同数量的

private static int GenerateRandomNumber(int seed, int max) 
{ 
    return new Random(seed).Next(max); 
} 

在我的机器,执行这个循环通过1500次迭代产生相同数量:

for (int i = 0; i < 1501; i++) 
      { 
       int random = GenerateRandomNumber(100000000, 999999999); 
       Console.WriteLine(random.ToString()); 
       Console.ReadKey(); 
      } 

我得到145156561,每一次迭代。

我没有紧迫的问题,我只是好奇这种行为,因为.Next(max)说:“返回一个非负数随机数字小于指定的最大值也许我不理解的东西基本。

+7

这正是'seed'的意思。 – SLaks 2011-03-10 19:01:46

+1

我现在明白了。我只是认为它至少通过智能感知呈现的方式并不那么明显。 – kd7 2011-03-10 19:03:51

回答

37

你总是播种一个新的实例使用相同的种子,然后抓住了第一个最大。通过使用种子,你就保证了相同的结果。

如果你想有一个静态的,随机的但是,由于Random不是线程安全的,所以在静态使用时需要一些同步。 ike:

private static Random random; 
private static object syncObj = new object(); 
private static void InitRandomNumber(int seed) 
{ 
    random = new Random(seed); 
} 
private static int GenerateRandomNumber(int max) 
{ 
    lock(syncObj) 
    { 
     if (random == null) 
      random = new Random(); // Or exception... 
     return random.Next(max); 
    } 
} 
+1

如果你需要很多随机数,这可能会杀死PC :-)如果你在C#4.0下,或者使Random对象线程静态,至少要使用SpinLock。 – xanatos 2011-03-10 19:06:32

+0

您应该使用双重检查锁定。 – SLaks 2011-03-10 19:08:44

+1

@SLaks:没有什么帮助 - Random.Next()不是线程安全的,所以你总是需要一个锁。这里的锁并不适用于懒惰实例...... – 2011-03-10 19:10:04

6

问题是您每次都创建一个具有相同种子编号的新Random实例。您应该创建一个单独的Random实例(如果需要,将其存储在静态中),并简单地调用该实例上的下一个方法。

随机数字的生成不是真正的随机数,更多详细信息请参阅this Wikipedia entry

3

伪随机数发生器通常通过选择一个种子,然后根据该种子生成一个确定性序列。每次选择相同的种子,您会生成相同的序列。

.NET中只有“2^32个不同的随机序列。

2

不知道内部工作是如何工作的..检查wiki,但它非常简单。

public class MathCalculations 
{ 
    private Random rnd = new Random(); 

    public Int32 getRandom(Int32 iMin, Int32 iMax) 
    { 
     return rnd.Next(iMin, iMax); 
    } 
} 

public class Main 
{ 
    MathCalculations mathCalculations = new MathCalculations(); 
    for (int i = 0; i < 6; i++) 
    { 
     getRandom(0,1000); 
    } 
} 

会产生数字1,数字,3号,号码4,5号,Number6(1种,许多数字1个序列,随机*不是真的,但约。*)

不过,若你这样做:

public class MathCalculations 
{ 
    public Int32 getRandom(Int32 iMin, Int32 iMax) 
    { 
     Random rnd = new Random(); 
     return rnd.Next(iMin, iMax); 
    } 
} 

public class Main 
{ 
    MathCalculations mathCalculations = new MathCalculations(); 
    for (int i = 0; i < 6; i++) 
    { 
     getRandom(0,1000); 
    } 
} 

现在,您将获得数字1,数字1,数字1,数字1,数字1,数字1(1种,多的数字6组相同的序列,总是选择从每个等于序列相同的起始编号)..在某些时候,数字1将是不同的,因为种子会随着时间的推移而变化......但是你需要等待一些时间我为此,尽管如此,你从来没有从序列中挑选数字2。

原因是,每次您使用相同的种子生成一个新的序列时,因此该序列一遍又一遍地重复,每次您的随机生成将会选择序列中的第一个数字,同样的种子,当然总是一样的。

不知道这是否由技术上的随机发生器的基础方法是正确的,但这就是它的行为。

7

迪尔伯特也遇到了同样的问题早在2001年:

http://dilbert.com/strips/comic/2001-10-25/

巧合吗?

我不这么认为。

而且random.org同意:http://www.random.org/analysis/

+4

在这里没有幽默的空间,真的吗? – dbrin 2014-01-30 16:29:39

+0

虽然这个链接可能回答这个问题,但最好在这里包含答案的重要部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 - [来自评论](/ review/low-quality-posts/18480928) – jv42 2018-01-10 20:01:37

+0

尽管尊重@ jv42,但我不能再现漫画内容,所以在这种情况下,链接是合理的。 – dbrin 2018-01-10 23:33:21

0

倘若有人正在寻找一个“快速和肮脏”,“解决方案”(我谨慎使用这个词),那么这将足以满足大多数。

int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds); 
Random rand = new Random(secondsSinceMidnight); 
var usuallyRandomId = rand.Next(); 

请注意我的使用通常是随机的。我同意标记为答案的项目是更正确的方式。

1

萨拉姆全部, 好吧,它也让我疯了。答案很简单。在生成随机数之前更改种子。

实施例: 我要生成1之间的随机数到10

Random rnd = new Random(DateTime.Now.Seconds); 
int random_number = rnd.Next(10); 

放入一个循环内,并且运行它的三倍。它会发出10以下的随机数。