【问题标题】:Why does Random.Next() always return the same number [duplicate]为什么 Random.Next() 总是返回相同的数字[重复]
【发布时间】:2011-07-12 23:21:49
【问题描述】:

考虑这种方法:

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) 表示“返回小于指定最大值的非负 随机 数。也许我不是了解一些基本的东西。

【问题讨论】:

  • 这正是seed 的意思。
  • 我现在明白了。我只是认为它至少通过智能感知呈现的方式并不那么明显。

标签: c# random clr


【解决方案1】:

您总是用相同的种子播种一个新实例,然后获取第一个最大值。通过使用种子,您可以保证相同的结果。

如果你想生成一个产生不同结果的静态随机数,你应该重新设计一下。但是,由于 Random 不是线程安全的,因此在静态使用时需要一些同步。比如:

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);
     }
}

【讨论】:

  • 如果您需要许多随机数,这可能会杀死 PC :-) 如果您在 C# 4.0 下,至少使用 SpinLock,或者使 Random 对象 Thread Static。
  • 你应该使用双重检查锁定。
  • @SLaks:并没有真正的帮助 - Random.Next() 不是线程安全的,所以你总是需要一个锁。这里的锁不适用于惰性实例化...
  • @xanatos: True- 如果您从多个线程中使用它,我不建议您这样做。在这种情况下,ThreadLocal 可能是一个更好的选择,但它有其独特的问题,除非需要,否则我会避免。
  • 作为免费奖励,我将在 Random AND ThreadLocal 上添加 Jon Skeet 的一篇文章! :-) csharpindepth.com/Articles/Chapter12/Random.aspx
【解决方案2】:

Dilbert 早在 2001 年就遇到过同样的问题:

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

巧合?

我不这么认为。

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

【讨论】:

  • 在 SO 中没有幽默的余地,真的吗?
  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
  • 恕我直言@jv42,但我无法复制漫画内容,所以在这种情况下链接是合理的。
  • 你不能,它可能没用。您在此处发布答案,其中应包含解决问题的有用内容。最初的问题包含一些用于生成随机数的代码中的错误,这与 RNG 理论无关。
  • 虽然我很欣赏幽默,尤其是 Dilbert,但我只是认为您的“回答”没有帮助。
【解决方案3】:

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

随机数生成并不是真正随机的,请参阅this Wikipedia entry 了解更多详情。

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      不确定内部是如何工作的。请查看 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);
          }
      }
      

      将生成 Number1、Number2、Number3、Number4、Number5、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);
          }
      }
      

      您现在将获得 Number1, Number1, Number1, Number1, Number1, Number1(1 个种子,6 个相等的数字序列,总是从每个相等的序列中选择相同的起始数字).. 在某些时候 Number1 会有所不同,因为种子会随着时间而改变.. 但是您需要等待一段时间,但是,您永远不会从序列中选择 number2。

      原因是,每次您生成具有相同种子的新序列时,因此该序列一遍又一遍地相同,并且每次您的随机生成时都会选择其序列中的第一个数字,它具有相同的种子,当然总是一样的。

      不确定随机生成器的底层方法在技术上是否正确,但这就是它的行为方式。

      【讨论】:

        【解决方案6】:

        向所有人致敬, 好吧,它也让我发疯了。答案很简单。在生成随机数之前更改种子。

        示例: 我想生成 1 到 10 之间的随机数

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

        将它放在一个循环中并运行三遍。它会给出10以下的随机数。

        【讨论】:

        • 对于任何偶然发现这一点的人来说,这是行不通的,因为如果迭代足够大,种子将不是唯一的。
        【解决方案7】:

        如果有人正在寻找“快速而肮脏”的“解决方案”(我谨慎使用该术语),那么这对大多数人来说就足够了。

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

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

        【讨论】:

          猜你喜欢
          • 2013-04-17
          • 2010-12-11
          • 2013-12-23
          • 1970-01-01
          • 2019-06-26
          • 1970-01-01
          相关资源
          最近更新 更多