为什么在生成Random()数字时会得到奇怪的结果?

时间:2013-09-28 21:54:12

标签: c# arrays random

我的计划需要:

一个。生成一个由0到9的20个随机整数的数组。搜索数字7的第一个匹配项(如果有),并在数组中报告其位置。

湾重复计算1000次,对于数组中的每个位置,报告数组中第一次出现7次的次数

然而,每当我运行程序时,我都会得到奇怪的结果(每次都不同),例如:

  1. 在任何位置都找不到七人
  2. 在一个位置找到1000个七人组,在其他任何地方找不到七人组
  3. 在2个位置发现了数百个七人组,其他地方都找不到。
  4. 有没有人知道我的程序有什么问题?

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
    
        namespace Week_6_Project_2
        {
        class Program
        {
    
        static int intArrayLength = 20;
        static int[] resultsArray = new int[intArrayLength];
    
        public static Array generateRandomArray() {
            int[] randomNumberArray = new int[intArrayLength];
            Random random = new Random();
            int popcounter = 0;
            while (popcounter < intArrayLength) {
                randomNumberArray[popcounter] = random.Next(0, 10);
                popcounter += 1;
            }
            return randomNumberArray;
        }
    
        public static void searchForSevens()
        {
            int counter = 0;
            int[] randomArray = (int[])generateRandomArray();
            while (counter < intArrayLength)
            {
                if (randomArray[counter] == 7)
                {
                    resultsArray[counter] += 1;
                    counter = intArrayLength;
                }
                counter += 1;
            }
        }
        static void Main()
        {
            int searchCounter = 0;
            while (searchCounter < 1000)
            {
                searchForSevens();
                searchCounter += 1;
            }
    
            int displayCounter = 0;
            while (displayCounter < intArrayLength)
            {
                Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, resultsArray[displayCounter]);
                displayCounter += 1;
            }
            Console.ReadLine();
    
        }
        }
        }
    

5 个答案:

答案 0 :(得分:6)

您的主要问题是每个searchForSevens()测试只需要一小部分时间,而Random类使用时钟自动播种。然而,时钟具有有限的分辨率。结果是许多(有时是全部)随机序列都是相同的。最多只有2到3个不同的结果集。

这个单线程程序的简单修复是使用1个静态的Random实例。

答案 1 :(得分:3)

每次调用Random方法时,您都会实例化generateRandomArray的新实例。由于随机数生成器使用当前时间作为种子,同时实例化两个Random个实例会导致生成相同的数字,这可以解释您的意外结果。

要解决您的问题,您应该只实例化一个Random实例,将其存储在私有字段中,并在每次调用Next方法时重复使用它。

答案 2 :(得分:0)

我不会回答,但会尝试对那些认为他们需要更多随机实例的人进行类比...

假设您需要用1-6中的随机数填充6张纸。问问自己:你需要6个骰子或一个来完成这项工作吗?如果你回答你需要不止一个骰子,那就问问自己:每次投掷不同的骰子而不是相同的骰子有多么不同或更随机?

我的意思是,如果你掷骰子,下一次掷骰子的机会将不会比任何其他数字更少。它违背了直觉,但它在数学上和统计上都是如此。

答案 3 :(得分:-1)

我假设的问题源于这样一个事实:Random()使用当前时间作为种子。并且计算发生得如此之快,以至于每次调用new Random()时,它都使用相同的时间。所以你得到相同的数字序列。

要解决这个问题,你只需要自己设置种子,每个周期都应该增加种子。

long base = DateTime.Now.TotalMilliseconds;
Random rand = new Random(base+searchCounter);

..类似的东西。

答案 4 :(得分:-2)

在原始代码中,您快速连续[broken example based on OP's original code]调用Random方法,因此使用相同的数字播种该方法,从而产生重复的“随机”数字。创建静态成员将确保随机性,因为您只创建了它的单个实例。

尝试像这样创建random的单个静态实例。 [static member example]

static readonly Random Random = new Random();

基于此,以下是我将如何解决您的特定问题。

using System;

namespace Week_6_Project_2
{
    class Program
    {
        // ******************************************
        // THIS IS A SINGLE INSTANCE OF Random.
        // read below as to why I'm seeding the instantiation of Random();
        static readonly Random Random = new Random(Guid.NewGuid().GetHashCode());
        // ******************************************

        private const int IntArrayLength = 20;
        static readonly int[] ResultsArray = new int[IntArrayLength];

        public static Array GenerateRandomArray()
        {
            var randomNumberArray = new int[IntArrayLength];

            var popcounter = 0;
            while (popcounter < IntArrayLength)
            {
                randomNumberArray[popcounter] = Random.Next(0, 10);
                popcounter += 1;
            }
            return randomNumberArray;
        }

        public static void SearchForSevens()
        {
            var counter = 0;
            var randomArray = (int[])GenerateRandomArray();
            while (counter < IntArrayLength)
            {
                if (randomArray[counter] == 7)
                {
                    ResultsArray[counter] += 1;
                    counter = IntArrayLength;
                }
                counter += 1;
            }
        }
        static void Main()
        {
            var searchCounter = 0;
            while (searchCounter < 1000)
            {
                SearchForSevens();
                searchCounter += 1;
            }

            var displayCounter = 0;
            while (displayCounter < IntArrayLength)
            {
                Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, ResultsArray[displayCounter]);
                displayCounter += 1;
            }
            Console.ReadLine();

        }
    }
}

进一步了解Random()

除了上面的答案,有时需要种子Random(int);(我喜欢使用Guid的HashCode)来确保进一步的随机性。这是因为默认种子使用来自文档[microsoft]的时钟具有有限分辨率的时钟。如果您的类快速连续多次实例化(<16ms),您将从时钟中获得相同的种子...这会破坏内容。
[example of seeded Random(int) run in rapid succession with random results]

  

“使用无参数构造函数以紧密连续的方式创建不同的随机对象,创建随机数生成器,生成相同的随机数序列。”

当我说你不应该在循环的每次迭代中实例化一个新的Random时听到我 - 使用静态成员


实现自己的种子的另一个有效理由是,当您想 重新创建 随机序列[example of two identical lists based on same seed]时。重复使用相同的种子将重新创建序列,因为序列基于种子。

注意:其他人可能会认为播种它是不必要的[link],但我个人认为,对于额外的几次按键和时钟上的微观命中,你可能会增加概率独特的种子。它不会伤害任何东西,在某些情况下它可以提供帮助。