【问题标题】:How can I generate truly (not pseudo) random numbers with C#?如何使用 C# 生成真正(非伪)随机数?
【发布时间】:2010-11-17 01:44:47
【问题描述】:

我知道 Random 类可以生成伪随机数,但有没有办法生成真正的随机数?

【问题讨论】:

  • 什么是truly random?即使是掷骰子也不是随机的。滚动取决于高度、施加的力、风等。你的大脑无法处理这些数据。

标签: c# algorithm math


【解决方案1】:

这里的答案有两个主要方面。您应该注意一些非常重要的微妙之处...

简单的方法(简单实用)

RNGCryptoServiceProvider 是 BCL 中 Crypto API 的一部分,应该可以为您完成这项工作。从技术上讲,它仍然是一个生成的伪随机数,但“随机性”的质量要高得多——顾名思义,它适用于加密目的。

还有其他具有高质量伪随机生成器的加密 API。 Mersenne twister 等算法非常流行。

与 BCL 中的 Random 类相比,它明显更好。例如,如果您将Random 生成的数字绘制在图表上,您应该能够识别出模式,这是一个很弱的信号。这主要是因为该算法仅使用固定大小的种子查找表。

The Hard Way(高质量的理论随机性)

要生成真正的随机数,你需要利用一些自然现象,比如核衰变、微观温度波动(CPU温度是一个比较方便的来源)等等。然而,这要困难得多,当然需要额外的硬件。我怀疑实用的解决方案(RNGCryptoServiceProvider 或类似的)应该可以很好地为您完成这项工作。

现在,请注意,如果您确实需要真正的随机数,您可以使用Random.org 等服务,它会生成具有非常高随机性/熵的数字(基于atmospheric噪音)。数据可免费下载。尽管如此,这对于您的情况来说可能是不必要的复杂,尽管它确实为您提供了适合科学研究之类的数据。

最终选择权在您,但至少您现在应该能够做出明智的决定,了解 RNG 的各种类型和级别。

【讨论】:

  • 感谢您的提示,我将尝试使用 RNGCryptoServiceProvider。我也可以试试核衰变……
  • @Max: 呵呵...我应该注意到一个更简单的方法是监控 CPU 温度,因为这是最容易获得的来源。但是,是的,请先查看RNGCryptoServiceProvider。如果您愿意描述上下文,我可以确认这是否足以满足您的使用需求。
  • @Douglas - 如果你从未得到重复的数字,那将表明随机性小于总随机数。
  • 我刚刚尝试了首页上的那个生成器,我得到了 25 和 43。两个完全不相关的数字,这不太可能!?这种惊人的事情让我脊背发凉。
  • @Nick:我说技术上只是因为 PRNG 通常被称为 RNG……但是,是的,我认为我已经明确区分了这两种类型及其方法。
【解决方案2】:

简短回答:仅使用 C#(即仅使用纯数学构造)无法直接生成 真正随机数

long(er) 答案:仅通过使用能够生成“随机性”的外部设备(例如 white noise generator or similar)并将该设备的输出捕获为伪随机数生成器 (PRG) 的种子。这部分可以使用 C# 来完成。

【讨论】:

  • +1 - 抓住问题的本质。根据定义,纯算法生成的任何东西都不可能是真正随机的。您需要一个外部模拟随机源,例如测量宇宙背景辐射的设备。
  • 很有趣的是,计算机无法产生看似如此简单的东西。他们不能使用其他元素,比如 CPU 温度吗?
  • @Max:你已经成功了。请参阅我对我自己的帖子的评论。然而,所有机器上的 CPU 温度仍远未达到 - 它可能是服务器设备的一个很好的解决方案。
  • @Max:随机性是难以捉摸的事情之一,因为它作为一个概念似乎很简单,但生成它的任务(人工或数学)即使不是不可能也非常复杂
  • 但是使用 C# 和“计算机”是不可能的说法是不正确的。计算机是一个真实的物理系统,其运行具有很大的随机性。只需要写入模拟监控设备来捕获它 - 例如您可以将内置麦克风指向风扇并捕捉一些噪音。
【解决方案3】:

只有在真正随机的物理输入设备为随机函数提供种子的情况下,才能生成真正的随机数。

科学界仍在争论(并且可能会持续很长时间)是否存在任何物理的和真正随机的东西。

伪随机数生成器是次优的,最好的很难预测。

【讨论】:

    【解决方案4】:

    正如约翰·冯·诺依曼 (John von Neumann) 开玩笑说的那样,“任何考虑用算术方法产生随机数字的人,当然都处于一种犯罪状态。”

    【讨论】:

      【解决方案5】:

      线程是旧的并已回答,但我想我还是会继续。这是为了完整性,人们应该知道一些关于 Random 在 c# 中的事情。

      至于真正的随机,你能做的最好的事情就是使用像 salsa20 或 RC4 之类的“安全伪随机生成器”(有时是这样)。它们通过了一系列测试,“高效”的对手试图将它们与随机区分开来。这会带来一定的成本,并且对于大多数用途来说可能是不必要的。

      c# 中的随机类在大多数情况下都非常好,它具有看起来随机的静态分布。但是 random() 的默认种子是系统时间。因此,如果您在“同时”获取大量随机数,它们将使用相同的种子并且将是相同的(“随机”是完全确定的,不要让它欺骗你)。由于随机类的缺点,相似的系统时间种子也可能产生相似的数字。 处理这个问题的方法是给你自己设置种子,比如

      Random random = new Random((int)DateTime.Now.Ticks & (0x0000FFFF + x));
      

      如果你创建了一个循环来获取一堆随机数,那么 x 是你增加的某个值。

      此外,使用 c# 对新变量(如 NextDouble() 进行随机扩展)有助于处理随机数,在这种情况下,将它们放入区间 (0,1) 以变为 unif(0,1),这种情况发生的是一个分布,您可以将其插入统计公式以创建统计中的所有分布。

      【讨论】:

      • 回过头来看,这个答案似乎暗示您使用大量随机对象来获取大量随机数。你没有,你使用一个并使用 random.next 很多。郑重声明,我认为 new Random(Guid.NewGuid().GetHashCode()) 是我最喜欢的,尽管这并不重要。
      【解决方案6】:

      看看使用像 YarrowFortuna 这样的算法和熵累积。这些算法的重点在于,它们通过了解过去的数字和用于生成它们的算法来跟踪熵,作为可用于预测未来数字的理论信息内容的度量;他们使用密码技术将新的熵源折叠到数字生成器中。

      您仍需要外部随机数据源(例如hardware source of random numbers),无论是击键时间、鼠标移动时间、硬盘访问时间、CPU 温度、网络摄像头数据或股票价格,还是不管怎样——但无论如何,你会不断地将这些信息混合到熵池中,这样即使真正的随机数据速度很慢或质量很低,也足以让事情以一种不可预测的方式进行。

      【讨论】:

        【解决方案7】:

        我正在讨论基于 twitter 或其他社交网站之一构建一个随机数生成器。基本上使用 api 来提取最近的帖子,然后使用它来播种高质量的伪随机数生成器。它可能并不比随机关闭计时器更有效,但看起来很有趣。此外,它似乎是人们发布到 Twitter 上的大多数内容的最佳用途。

        【讨论】:

        • 这可能具有与从时间戳播种相同的攻击向量。
        【解决方案8】:

        我一直很喜欢这个想法,因为 60 年代的复古外观:

        Lavarand

        【讨论】:

          【解决方案9】:

          计算机中没有“真正的”随机性,一切都基于其他东西。对于一些(可行的)生成伪随机数据的方法,请尝试诸如 HD 温度池、CPU 温度、网络使用率(数据包/秒)以及可能的网络服务器点击/秒之类的方法。

          【讨论】:

          • There is no "true" random in computers,在现实生活中都没有。除非“随机”是指“我暂时无法预测的事情”。
          【解决方案10】:

          没有办法用计算机生成真正的随机数。真正的随机性需要一个外部源来监控某些自然现象。

          也就是说,如果您无法访问这样一个真正随机数的来源,您可以使用这样的“穷人”过程:

          • 创建一个由数字组成的长数组(10000 个或更多?)
          • 以标准方式使用当前时间播种的随机数填充数组
          • 当需要随机数时,在数组中生成一个随机索引并返回包含在该位置的数字
          • 在数组索引处创建一个新的当前时间种子随机数来替换使用的数字

          这个两步过程应该可以在一定程度上提高结果的随机性,而无需外部输入。

          这是一个用 C++ 实现上述算法的示例库:http://www.boost.org/doc/libs/1_39_0/libs/random/random-generators.html

          【讨论】:

          • @ryeguy 这正是它的工作原理。以下是 C++ 代码的详细解释:boost.org/doc/libs/1_39_0/libs/random/random-generators.html
          • +1,因为这不值得负分。建议的方法可能不会像使用更好的算法那样提高随机性的质量,但它仍然是一个公平的观点。
          • 问题是关于真正的随机性,这个答案通过将随机性限制在已经选择的随机数池中来抑制随机性。我也怀疑这将如何改善(伪)随机性??
          【解决方案11】:

          只是为了澄清大家说 C# 或您的计算机上没有可用的 True RNG 是错误的。多核处理器本质上是真正的 RNG。非常简单地通过利用处理器旋转,您可以生成没有可识别模式的布尔值。从那里,您可以通过将布尔值用作位并通过将位相加来构造数字来生成您想要的任何数字范围。

          是的,这比纯数学解决方案慢很多,但纯数学解决方案总会有一个模式。

          public static bool GenerateBoolean()
          {
              var gen1 = 0;
              var gen2 = 0;
              Task.Run(() =>
              {
                  while (gen1 < 1 || gen2 < 1)
                      Interlocked.Increment(ref gen1);
              });
              while (gen1 < 1 || gen2 < 1)
                  Interlocked.Increment(ref gen2);
              return (gen1 + gen2) % 2 == 0;
          }
          

          【讨论】:

            【解决方案12】:

            此代码将返回一个介于minmax 之间的随机数:

            private static readonly Random random = new Random();
            private static readonly object syncLock = new object();
            public int RandomNumber(int min, int max)
            {
                lock (syncLock)
                { // synchronize
                    return random.Next(min, max);
                }
            }
            

            用法:

            int randomNumber = RandomNumber(0, 10); // a random number between 1 and 10
            

            【讨论】:

            • 您是否阅读了整个问题? OP 说他知道 Random 类,他(此时是因为这个问题已经很老了)正在寻找一种生成“真正随机数”的方法。
            • 那是来自OP的引用,基本上Random类生成的数字只有Pseudo Random。如果您阅读了一些回答这个问题的答案,您应该更好地了解 OP 的含义。
            • 感谢您的反馈。我会详细了解这个主题。
            • 可能不是 OP 想要的,但这是我想要的,谢谢,好主意。
            猜你喜欢
            • 2016-03-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-30
            • 2015-08-07
            • 1970-01-01
            • 2023-01-03
            • 1970-01-01
            相关资源
            最近更新 更多