【问题标题】:Random number generating loop generates the same number [duplicate]随机数生成循环生成相同的数字[重复]
【发布时间】:2013-10-22 14:57:26
【问题描述】:

我还是 C# 新手,我正在尝试构建一个模拟掷硬币 X 次的短程序:

        // Declarations
        int headCount = 0;
        int tailCount = 0;

        // Main Program Logic
        Console.WriteLine("Press enter to begin");
        Console.ReadLine();
        for (int x = 1; x <= 25; x++)
        {
            Random rnd = new Random();
            int flip = rnd.Next(1, 3);
            if (flip == 1)
            {
                Console.WriteLine("Heads");
                headCount++;
            }
            else
            {
                Console.WriteLine("Tails");
                tailCount++;
            }
        }
        Console.WriteLine("Heads came up {0} times.", headCount);
        Console.WriteLine("Tails came up {0} times.", tailCount);
        if (headCount > tailCount)
        {
            Console.WriteLine("Heads wins.");
        }
        else
        {
            Console.WriteLine("Tails wins.");
        }

        // END OF DOCUMENT
        Console.ReadLine();
    }

现在,我确信我的代码是可靠的,但是,当我运行程序时遇到了问题。在上面的代码中,想法是每次执行 for 循环时都会生成一个新的随机数(1 或 2)。实际上,十分之九,它第一次生成一个数字,然后将该数字用于循环的其余执行。

每个人偶尔一次,结果大约是 50/50(您在统计上所期望的),但通常它只是重复 25 次的相同结果。

请注意,我在循环内声明了翻转变量。我已经在循环中和循环之前来回移动它,并且更改似乎没有任何效果。

是我做错了什么还是 C# 喜欢抛出统计异常?

【问题讨论】:

  • 每个人都给出了正确答案,这里有一些关于随机数的额外阅读:msdn.microsoft.com/en-us/library/…
  • 如果您需要更好的随机性,请考虑使用 RNGCryptoServiceProvider,如下所述。
  • 解决问题的最快方法是在循环中使用之前生成大量随机数。然后生成一个随机数组 start_index 数字(如果您打算使用从 0 索引开始的数组,则不生成)。当程序进入循环时,使用 start_index 数字从数组中获取第一个生成的随机数。然后在每个循环迭代中获取 (index+x)。还要检查并重置 start_index,如果它到达带有随机数的数组的末尾。

标签: c# for-loop random


【解决方案1】:

原因是你一直打电话给new Random()。相反,您应该在循环之外构建它,然后调用 .next(int,int)

 Random rnd = new Random();
 for (int x = 1; x <= 25; x++)
 {
        int flip = rnd.Next(1, 3);
        //do stuff
 }

【讨论】:

    【解决方案2】:

    在循环之外实例化您的随机数生成器,以便它能够正确生成随机数。

    原因是种子主要基于 CPU 时钟。请记住,计算机只能生成“伪随机”数字。为此,他们使用种子和一些数学。如果使用的种子来自同一时间(因为循环中的代码以纳秒为单位执行)每个随机数都是相同的。

    当在循环之外使用时,种子将为每次调用时创建不同的随机数提供基础。

    【讨论】:

      【解决方案3】:
      Random rnd = new Random();
      

      这是你的问题。每次循环都在重新初始化生成器。由于您没有提供种子,因此默认构造函数使用精确到毫秒的当前时间作为种子。由于您的循环运行得非常快,因此该数字对于循环的大多数迭代都是相同的,从而导致您重复生成相同的数字。

      解决办法: 将其移出循环 =)

      延伸阅读:Pseudo-Random Number Generators

      【讨论】:

        【解决方案4】:

        您需要在循环之外初始化随机数生成器!

                Random rnd = new Random();
                Console.WriteLine("Press enter to begin");
                Console.ReadLine();
                for (int x = 1; x <= 25; x++)
        

        编辑: 实际上,我只需将随机初始化程序移到 Console.ReadLine() 上方即可从您的代码中获得良好的分布

        编辑 2: 如果您想要 MUCH 更好的随机数,请考虑使用 RNGCryptoServiceProvider。

        RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();
        var randomByte = new byte[1];
        rnd.GetBytes(randomByte);
        

        虽然使用起来不如 Random 友好(因为它给你的是随机字节而不是整数),但它提供了更好的随机性。然而,这个随机数生成器足以用于密码学,而 Random 不应该用于密码学。

        【讨论】:

        • give it a somewhat random seed 是什么意思?要生成随机数,您需要提供随机种子吗?好笑!
        • Random 实际上是一个返回看似随机的数字的函数。然而......它仍然只是一个功能。因此,每次您从相同的种子值开始时,您都会从中得到相同的“随机”数字字符串。
        • 我已经知道了,但是要获得随机数,您需要随机种子吗?那你将如何生成种子?与另一个具有随机种子的随机类?
        • @SriramSakthivel 通常你会根据时间使用一些东西。在这种情况下,使用默认构造函数的 Random() 它使用时间相关的种子值。
        • 我也知道,IIRC 它使用Environment.TickCount。你的意思是什么?
        猜你喜欢
        • 1970-01-01
        • 2011-06-18
        • 1970-01-01
        • 1970-01-01
        • 2021-12-31
        • 1970-01-01
        • 2019-05-21
        • 2011-06-12
        • 1970-01-01
        相关资源
        最近更新 更多