我知道 Random 类可以生成伪随机数,但是是否有一种方法可以生成真正的随机数?
这里的答案有两个主要方面。有一些非常重要的微妙之处需要您注意...
RNGCryptoServiceProvider
是BCL中的Crypto API的一部分,应该可以为您完成工作。它仍然是技术上的伪随机数生成器,但“随机性”的质量更高 - 适用于加密目的,正如名称所示。
还有其他具有高质量伪随机生成器的加密API可用。例如Mersenne twister算法非常受欢迎。
与BCL中的Random
类相比,它要好得多。例如,如果在图表上绘制由Random
生成的数字,则应该能够识别出模式,这是弱点的明显标志。这在很大程度上是因为该算法仅使用固定大小的种子查找表。
要生成真正的随机数,您需要利用一些自然现象,例如核衰变,微小的温度波动(CPU温度是一个相对方便的来源),等等。但是,这要困难得多,并且需要额外的硬件。我怀疑实际解决方案(RNGCryptoServiceProvider
或类似解决方案)应该可以完美地为您完成工作。
简短回答:仅使用C#(即仅使用纯数学构造),不可能直接生成真正的随机数。
长一点的回答:只有通过使用能够产生“随机性”的外部设备,如白噪声发生器或类似设备来捕获该设备的输出作为伪随机数生成器(PRNG)的种子才可能实现。这一部分可以使用C#完成。
只有真正随机的物理输入设备提供种子才能生成真正的随机数。
科学界仍在争论是否存在物理上真正的随机现象(并且可能会持续很长时间)。
伪随机数生成器是次优选择,而最好的伪随机数生成器非常难以预测。
正如约翰·冯·诺伊曼开玩笑所说,“任何考虑使用算术方法生成随机数字的人,当然是处于一种罪恶状态。”
这篇文章虽然有点老,但是我还是想继续讨论一下。这样做是为了保证完整性,让人们了解一些关于C#中随机数的知识。
如果要真正地获得随机数,最好的方法就是使用“安全伪随机生成器”(如salsa20或RC4)。它们通过了一系列测试,其中“高效”的对手试图将它们与随机数区分开来。这种方法也有一定的代价,对于大多数用途来说可能并不必要。
C#中的Random类通常表现得很好,具有看起来随机的静态分布。但是random()的默认种子是系统时间。因此,如果在“同一时间”取很多个随机数,则它们使用相同的种子并且会是相同的(“随机”是完全确定性的,不要被它所迷惑)。由于Random类的缺陷,类似的系统时间种子也可能产生相似的数字。
解决这个问题的方法是设置自己的种子,例如:
Random random = new Random((int)DateTime.Now.Ticks & (0x0000FFFF + x));
假设你已经创建了一个循环以获得大量随机数,那么x是你递增的一些值。
此外,在c#中,对于你的新变量使用类似NextDouble()的随机扩展函数可以帮助操作随机数。在这种情况下,将它们强制转换到区间(0,1)中变为unif(0,1),这是一个您可以插入到统计公式中创建所有统计分布的分布。
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;
}
计算机中不存在真正的随机数,一切都基于其他事物。为了生成伪随机数据,可以尝试使用诸如硬盘温度、CPU温度、网络使用情况(每秒钟的数据包数)以及可能的网站访问量等池子。