1

我的程序需要:

一个。生成一个包含 20 个从 0 到 9 的随机整数的数组。搜索数字 7 的第一次出现(如果有),并报告其在数组中的位置。

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

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

  1. 在任何位置都找不到七人组
  2. 在一个位置发现 1000 个七人组,而在其他任何地方都没有发现七人组
  3. 在 2 个位置发现了数百个 7,在其他任何地方都没有发现。

有谁知道我的程序有什么问题?

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

    }
    }
    }
4

5 回答 5

6

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

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

于 2013-09-28T21:59:46.367 回答
3

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

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

于 2013-09-28T22:02:26.600 回答
-1

我不会回答,但会尝试为那些认为他们需要不止一个 Random 实例的人做一个类比......

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

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

于 2013-09-29T18:34:48.867 回答
-1

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

要解决这个问题,您只需要自己设置种子,每个周期增加它就足够了。

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

..类似的东西。

于 2013-09-28T22:01:47.617 回答
-2

在您的原始代码中,您正在Random快速连续调用该方法[基于 OP 原始代码的破碎示例],从而为该方法播种相同的数字,从而导致重复的“随机”数字。创建静态成员将确保随机性,因为您只创建它的单个实例。

尝试创建一个random这样的静态实例。[静态成员示例] .

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),您将从时钟中获得相同的种子......这会破坏东西。[随机结果快速连续运行的
示例]Random(int)

“使用无参数构造函数连续创建不同的 Random 对象会创建生成相同随机数序列的随机数生成器。”

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


实现自己的种子的另一个正当理由是当您想要重新创建一个随机序列[基于相同种子的两个相同列表的示例] 时。重新使用相同的种子将重新创建序列,因为序列是基于种子的。

注意:其他人可能会说没有必要播种[link],但我个人认为,对于额外的几次击键和对时钟的微小打击,您还不如增加唯一种子的概率。它不会伤害任何东西,在某些情况下它可以提供帮助。

于 2013-09-28T22:39:13.777 回答