如何用C#生成真正的(非伪)随机数?

时间:2009-08-05 15:45:55

标签: c# algorithm math

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

12 个答案:

答案 0 :(得分:54)

这里的答案有两个主要方面。有一些非常重要的细微之处你应该给予应有的关注......

简单方法(为了简单和实用)

RNGCryptoServiceProvider,它是BCL中Crypto API的一部分,应该为您完成工作。它在技术上仍然是生成的伪随机数,但“随机性”的质量要高得多 - 适合加密目的,正如名称所暗示的那样。

还有其他具有高质量伪随机生成器的加密API。诸如Mersenne twister之类的算法非常受欢迎。

将此与BCL中的Random类进行比较,效果明显更好。例如,如果您在图表上绘制由Random生成的数字,您应该能够识别模式,这是弱点的强烈迹象。这主要是因为算法只使用固定大小的种子查找表。

艰难的方式(高质量的理论随机性)

要生成真正的随机数,您需要利用一些自然现象,例如核衰变,微观温度波动(CPU温度是一个相对便利的来源),仅举几例。然而,这当然要困难得多,并且需要额外的硬件。我怀疑实际的解决方案(RNGCryptoServiceProvider或者其他)应该能够很好地完成这项工作。

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

最终选择权归你所有,但至少你应该能够做出信息性的决定,了解各种类型和级别的RNG。

答案 1 :(得分:12)

简短回答:不能直接使用C#生成 TRULY RANDOM NUMBERS (即仅使用纯粹的数学结构)。

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

答案 2 :(得分:4)

如果存在为随机函数提供种子的真正随机物理输入设备,则只能生成真随机数。

科学界是否仍然存在争论(可能会持续很长时间)。

伪随机数生成器是下一个最好的东西,最好的是非常难以预测。

答案 3 :(得分:4)

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

答案 4 :(得分:3)

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

至于真正的随机性,你所希望做的最好的就是使用像salsa20或RC4这样的“安全伪随机生成器”(有时候是一种)。他们通过了一系列测试,“有效”的对手试图将它们与随机区分开来。这需要一定的成本,对于大多数用途来说可能是不必要的。

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

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

其中x是你增加的某个值,如果你已经创建了一个循环来获取一堆随机数,比如说。

同样使用c#random extension,你的新变量如NextDouble()可以帮助你操作随机数,在这种情况下,将它们变成区间(0,1)变为unif(0,1),这发生了您可以插入统计公式以在统计信息中创建所有分布的分布。

答案 5 :(得分:2)

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

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

答案 6 :(得分:1)

无法使用计算机生成真正的随机数。真正的随机性需要一个监视某种自然现象的外部源。

那就是说,如果你无法获得真正随机数字的来源,你可以使用这样一个“穷人”的过程:

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

这个两步过程可以在不需要外部输入的情况下改善结果的随机性。

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

答案 7 :(得分:1)

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

答案 8 :(得分:1)

我总是喜欢这个想法,对于60年代的复古外观:

Lavarand

答案 9 :(得分:1)

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

答案 10 :(得分:1)

此代码会在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

答案 11 :(得分:0)

只是为了澄清每个人都说C#或您的计算机上没有真正的RNG可用是错误的。多核处理器本身就是真正的RNG。非常简单地利用处理器旋转,您可以生成没有可辨别模式的bool。从那里你可以使用bools作为位生成你想要的任何数字范围,并通过将位加在一起来构造数字。

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

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;
}