【问题标题】:Random Number Generation - Same Number returned [duplicate]随机数生成 - 返回相同的数字 [重复]
【发布时间】:2011-06-18 20:26:03
【问题描述】:

可能的重复:
c# - getting the same random number repeatedly
Random number generator not working the way I had planned (C#)

我有一个构建整数队列的方法:

public Queue<int> generateTrainingInts(int count = 60)
    {
        Queue<int> retval = new Queue<int>();

        for (int i = 0; i < count; i++)
        {
            retval.Enqueue(JE_Rand.rInt(2001, 100));
        }

        return retval;
    }

JE_Rand.rInt() 只是一个委托给 Random 类的函数的函数:

public static int rInt(int exclUB, int incLB = 0)
    {
        Random rand = new Random(DateTime.Now.Millisecond);
        int t = rand.Next(incLB, exclUB);
        rand = null;            
        return t;
    }

但是当我调用 generateTrainingInts 时,每次都会排入相同的号码。但是,如果我将 rInt 更改为使用 Random 类的静态实例,而不是本地实例(具有上面定义的函数范围),那么它似乎可以正常工作(将随机整数排入队列)。有人知道为什么会这样吗?

编辑: 亲爱的回答者没有仔细阅读我的问题, 就像你们中的一些人指出的那样,我正在寻找一个很好的解释来解释为什么会发生这种情况。我不是在寻找相同数字生成问题的解决方案,因为我已经像上面所说的那样解决了这个问题。不过感谢您的热情 :) 我真的只是想了解这样的事情,因为我的第一个实现在概念上对我来说更有意义。

【问题讨论】:

  • 似乎是重复的...查看相关问题,例如 -stackoverflow.com/questions/1437825/…
  • 这是因为 Random 对象是从 Environment.GetTickCount 初始化的,这是一个毫秒计时器。因此,如果您在同一毫秒内调用 Random 构造函数两次,您将获得相同的初始值。
  • 当 rand 用相同的种子实例化(例如 DateTime.Now.Millisecond 在你的情况下),它将返回相同的值序列。您应该将其实例化一次(并将其存储在静态变量中),或者每次使用不同的种子。
  • 关于您的编辑:我认为这让许多开发人员感到厌烦的原因是名称本身,Random。他们认为它是“一个随机数”。它真的应该被称为RandomSequence 或类似的东西。那么就更明显的是没有必要继续实例化新的了。
  • @Dan Tao 这是一个很好的观点。虽然我一直都知道随机意味着伪随机,但在实践中从来没有分离过这些概念,即使用随机数生成器总是被视为真正随机的,即使它不是因为实现对开发人员隐藏...跨度>

标签: c# random


【解决方案1】:

您需要保留相同的Random 对象。将其作为静态成员放在您的静态方法之外

private static Random rand = new Random();

public static int rInt(int exclUB, int incLB = 0)
{
    int t = rand.Next(incLB, exclUB);
    return t;
}

编辑
原因是用于初始化Random 的时钟分辨率有限。 Random 的后续初始化将在随机序列中获得相同的起始位置。当重复使用同一个 Random 时,总是会生成随机序列中的下一个值。

【讨论】:

  • OP 已经尝试过了,并在问为什么
  • 为什么在生成后将 rand 分配给 null ?由于 rand 将在很短的时间范围内实例化,因此两个实例将获得相同的种子并返回相同的值,就像在作者的版本中一样。您应该将其设为静态并始终保持相同的实例。也可以使用具有不同种子的多个实例,例如使用“Guid.NewGuid().GetHashCode()”作为种子,但你会得到糟糕的表现。
  • 我看到你已经更正了你的代码示例。它是假的,但它现在应该可以工作了......
  • 我用这个 var seed = (int) DateTime.Now.Ticks; var random = new Random(seed);
【解决方案2】:

试试下面的代码,我想你会明白为什么:

void PrintNowAHundredTimes()
{
    for (int i = 0; i < 100; ++i)
    {
        Console.WriteLine(DateTime.Now);
    }
}

Random 对象一遍又一遍地获得相同的种子。这是因为DateTime.Now 返回的系统时间粒度很简单,是有限的。例如,在我的机器上,该值仅每 ~ 15 毫秒更改一次。因此,该时间段内的连续调用返回相同的时间。

我怀疑你已经知道,使用相同种子值初始化的两个 Random 对象将生成相同的随机序列。 (这就是为什么它在技术上被称为 pseudorandom。)

您还应该知道,即使在您的方法中本地实例化一个新的 Random 对象是有意义的,将其设置为 null 仍然没有任何作用(一旦方法退出,将不再引用无论如何,对象都会被垃圾回收)。

【讨论】:

    【解决方案3】:
    public class JE_Rand
    {
       private static Random rand= new Random(DateTime.Now.Millisecond);
    
        public static int rInt(int exclUB, int incLB = 0)
        {
            int t = rand.Next(incLB, exclUB);
            return t;
        }
    }
    

    【讨论】:

    • 为什么 rand = null?它将转储对象,下一次调用将抛出异常
    • @walter:这是一个旧答案,但我只是复制和粘贴他的代码并将新的 Random(....) 移到方法调用之外。不过你是 100% 正确的。我将编辑我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 2013-01-31
    • 1970-01-01
    • 2010-11-10
    • 2011-06-12
    • 1970-01-01
    相关资源
    最近更新 更多