创建一个真正的随机

时间:2011-11-29 09:58:24

标签: c# random

  

可能重复:
  Why does it appear that my random number generator isn't random in C#?
  How can I generate truly (not pseudo) random numbers with C#?

我创造了一个骰子游戏,骰子基于百分位数,1-100。

public static void Roll()
{
    Random rand = new Random((int)DateTime.Now.Ticks);
    return rand.Next(1, 100);
}

但我不认为这是基于当前时间的真实随机。

如果我这样做

for (int i = 0; i < 5; i++)
{
   Console.WriteLine("#" + i + " " + Roll());
}

它们都是相同的值,因为DateTime.Now.Ticks没有改变,它播种的数字相同。

我想我可以生成一个新的随机种子,如果由于当前时间种子是相同的,但它不像一个诚实的“重新滚动”

我应该怎么做才能尝试复制接近真实/诚实的骰子卷?我应该使用RNGCryptoServiceProvider类来生成卷吗?

6 个答案:

答案 0 :(得分:14)

DateTime.Now.Ticks的分辨率只有approximately 16ms,因此,如果您在16毫秒“广告位”内多次创建一个带有该重载的Random,则所有广告都会以相同的值播种因此你会得到相同的序列。

在您的循环外部初始化Random,以便生成单个Random序列,而不是每次在循环内创建它,这可能会导致Randoms以相同的值播种因此产生相同的序列。

<强>更新

我之前的观点是默认构造函数初始化Random且CPU滴答错误,默认构造函数实际使用Environment.TickCount,即:

  

一个32位有符号整数,包含自上次启动计算机以来经过的时间量(以毫秒为单位)。

仍然具有低分辨率。如果快速连续创建Random的多个实例,则可以在同一时隙内轻松创建它们,因此具有相同的种子值,并创建相同的序列。创建Random的单个实例并使用它。

<强>更新

除了您的评论之外,如果您希望跨多个线程生成随机序列,请参阅以下Jon Skeet文章,该文章讨论了线程安全的包装器:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

答案 1 :(得分:8)

Random这样的伪随机数生成器只能播种一次,所以:

private static Random _rand = new Random();
public static int Roll()
{
    return _rand.Next(1, 100);
}

(注意我的返回值为int而不是void;问题中引用的Roll函数会导致语法错误。) < / p>

但你的标题是“创造一个真正的随机”Random不会为你做那件事,它是一个pseudo-random数字生成器,意味着它是确定性的,如果你不知道种子就很难预测。通常这对于大多数用途来说足够好,但是如果你需要真正的随机性,你需要一个熵源。 http://random.org是一个受欢迎的。

答案 2 :(得分:4)

您应该只在Roll功能之外创建一次Random类,并使用唯一值为其播种。

每次调用Roll时都会重新创建随机数,这会导致“非随机数”。

答案 3 :(得分:1)

  

我应该使用RNGCryptoServiceProvider类来生成卷吗?

如果这是一场涉及金钱的严肃游戏,那么:是的。

答案 4 :(得分:0)

我假设您正在快速调用Roll()方法Now.Ticks是一样的?

解决这个问题的最简单方法是,每次调用Random()创建一个静态变量来保存Roll()的单个实例时,创建一个新的Random()实例。 / p>

答案 5 :(得分:0)

使用随机数生成器的常用方法是将它们播种一次,保存它们并在整个程序中反复调用它们。只要您在开始时从适当的值开始播种,就应该获得可接受的随机性 - 假设您正在使用的生成器正在使用函数返回适合您的目的的随机事物。因此,将Random实例保存在Roll()函数之外,在第一次使用时将其播种,然后每次需要另一个数字时,只需在其上调用Next()。

当你接下来的时候,计算机上没有真正的随机数生成,只有基于种子的伪随机序列。然而,人类在识别随机性方面很糟糕,所以通常都没问题。