【问题标题】:How do I seed a random class to avoid getting duplicate random values [duplicate]如何播种随机类以避免获得重复的随机值[重复]
【发布时间】:2010-12-19 15:15:02
【问题描述】:

我在静态类的静态方法中有以下代码:

Random r = new Random();
int randomNumber = r.Next(1,100);

我有这个循环,我一直得到相同的randomNumber

这里有什么建议吗?

【问题讨论】:

  • 为什么?您可以将种子传递给构造函数。你真的需要重新播种吗?为什么不能用新种子创建一个新种子?
  • 我不是在抱怨方法/构造函数的设计,而是人们如何理解它。他们只看到“new Random()”和“r.Next”,并认为它会为他们选择不同的种子,但事实并非如此。
  • schnaader:人们没有问题,因为他们无法重新播种Random 课程。他们真正的问题是他们滥用了它。
  • /同意 Mehrdad。添加种子方法,并在此示例中重新设置种子并不能解决问题。种子是基于时间戳的,并且鉴于此代码在紧密的 for 循环中运行以及现代计算机的速度,它将在同一“时间”重新播种。播种必须进行一次。

标签: c# random


【解决方案1】:

对我来说,一个好的种子一代是:

Random rand = new Random(Guid.NewGuid().GetHashCode());

这是非常随机的。种子总是不同的,因为种子也是随机生成的。

【讨论】:

  • +1 优雅的随机生成器!谢谢,这就是我在谷歌上搜索的。
  • 解决了我的问题,两个应用程序同时启动并获得完全相同的种子值。
  • 从技术上讲,基于 Guid 的种子不会是随机的,而是具有一定程度的独特性。此外,使用 GetHashCode() 可以降低唯一性,因为 Guid 可以采用比 int 更多的值。不过,对于许多(如果不是大多数)情况来说,这已经足够了。
  • @AndréChristofferAndersen 你怎么知道? dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/…
  • Guid.NewGuid() 实际上必须首先使用随机生成器来创建 GUID(以及其他数据,例如时间和位置)。它也比使用不带参数的new Random() 慢,后者从系统时间设置种子,而且随机性也不低。
【解决方案2】:

您不应在循环中创建新的Random 实例。尝试类似:

var rnd = new Random();
for(int i = 0; i < 100; ++i) 
   Console.WriteLine(rnd.Next(1, 100));

单个Random 实例生成的随机数序列应该是均匀分布的。通过快速连续地为每个随机数创建一个新的Random 实例,您可能会为它们播种相同的值并让它们生成相同的随机数。当然,在这种情况下,生成的序列将远非均匀分布。

为了完整起见,如果您确实需要重新设置 Random 的种子,您将使用新种子创建 Random 的新实例:

rnd = new Random(newSeed);

【讨论】:

  • 嗨,我对“种子”这个词感到困惑,它是如何工作的?以及它对Java.util中的Random Class有什么影响
  • @harigm:通常,(伪)随机数生成器是一种确定性算法,它给定一个初始数(称为 seed),生成一个足以满足统计随机性检验。由于该算法是确定性的,因此如果使用相同的种子进行初始化,该算法将始终生成完全相同的数字序列。这就是为什么系统时间(一直在变化的东西)通常用作随机数生成器的种子。
  • 当可预测性成为问题时(例如在线赌博),可能需要重新播种随机生成器。在这种情况下,除了使用更真实的随机生成器(如熔岩灯)之外,您应该比模式识别从攻击者端应用的速度更快 - 或使用短寿命生成器池(并随机选择,并确保没有两个生成器的种子具有相同的值,等等)
【解决方案3】:

有点晚了,但是 System.Random 使用的implementationEnvironment.TickCount

public Random() 
  : this(Environment.TickCount) {
}

这避免了必须从 long 中转换 DateTime.UtcNow.Ticks,这无论如何都是有风险的,因为它不代表自系统启动以来的滴答声,而是“自午夜 12:00:00 以来经过的 100 纳秒间隔数, 0001 年 1 月 1 日(公历 0001 年 1 月 1 日 0:00:00 UTC)"。

正在为 TestApi 的 StringFactory.GenerateRandomString 寻找一个好的整数种子

【讨论】:

  • 如果是testApi,就用数字4,确定性好,测试方便
  • @hashtable 这通常是个好主意,但并非所有测试都是单元测试。在系统/集成测试中,引入较少可预测的行为可以增加测试表面 - 如果您没有资源在单个测试运行中检查每个可能的输入,这很有用。
  • 我们在我们的应用程序中遇到了问题,并行线程被同时释放(偶然),结果是每个线程都获得了相同的随机种子,因为它们是在同一个滴答声中触发的。 Guid 技巧似乎不会发生这种情况。
【解决方案4】:

如果由于某种原因您不能一次又一次地使用相同的Random,请尝试使用一直在变化的东西来初始化它,比如时间本身。

new Random(new System.DateTime().Millisecond).Next();

记住这是不好的做法。

编辑:默认构造函数已经从时钟中获取种子,并且可能比我们做得更好。引用 MSDN:

Random() :使用与时间相关的默认种子值初始化 Random 类的新实例。

下面的代码可能是你最好的选择:

new Random().Next();

【讨论】:

  • 这个怎么样? new Random(DateTime.Now.Millisecond).Next() 因为它获取当前毫秒。不过,我喜欢您关于“使用一直在变化的事物进行初始化,例如时间本身”的想法。另外,如果我们在每次迭代中添加一个 Thread.Sleep(1),它将是真正随机的。
  • 你会得到一个(一点点)更好的随机性,通过播种 Random 一个更大的不太可预测的数字,比如 new Random((int)DateTime.Now.Ticks)
  • 我相信默认种子是自系统启动时间以来的滴答声。
  • 如果 Random 类在同一毫秒内被多次初始化(例如在快速循环中),这将毫无帮助。 DateTime.Now.Ticks 更新也不够快。
  • 与 new Random() 相同的问题,“使用与时间相关的默认种子值初始化 Random 类的新实例。”
【解决方案5】:
public static Random rand = new Random(); // this happens once, and will be great at preventing duplicates

注意,这不能用于加密目的。

【讨论】:

  • 请注意,与 Java 不同,.NET 中的Random 不是线程安全的。在不同线程上调用 Next 时没有适当的锁定机制可能会导致随机数生成器的内部状态损坏。
  • @Mehrdad:或者更糟;我让它抛出异常。
  • @Jason:在大多数情况下,获得异常比处理糟糕的结果要好。我宁愿让我的在线扑克应用程序崩溃也不愿轻易预测
  • @PPC 在那种情况下你应该选择crypto random
  • OP 对线程安全只字未提。只是快速调用。
【解决方案6】:

这对我有用:

private int GetaRandom()
    {
        Thread.Sleep(1);
        return new Random(DateTime.Now.Millisecond).Next();
    }

【讨论】:

  • 使当前线程进入睡眠状态会导致大量并发问题。您实际上是在锁定您正在使用的当前线程,我怀疑在大多数情况下这将是您的主应用程序线程。为了完成这项工作,我建议将您的 RNG 隔离到它自己的线程中,这样它就可以被认为是线程安全的,并且可以异步使用它。
【解决方案7】:

一个好的种子初始化可以这样完成

Random rnd = new Random((int)DateTime.Now.Ticks);

刻度将是唯一的,并且转换为可能具有松散值的 int 是可以的。

【讨论】:

  • 不像你想象的那么独特。
【解决方案8】:

我在大多数情况下都使用它,如果需要重复序列,请保留种子

    var seed = (int) DateTime.Now.Ticks;
    var random = new Random(seed);

    var random = new Random((int)DateTime.Now.Ticks);

【讨论】:

    猜你喜欢
    • 2019-06-15
    • 1970-01-01
    • 2023-03-23
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    相关资源
    最近更新 更多