为什么我的随机数生成器在C#中不是随机的?

时间:2009-05-31 17:39:46

标签: c# random

我正在使用Microsoft Visual C#2008 Express。

我找到了这段代码:

    public static int RandomNumber(int min, int max)
    {
        Random random = new Random();

        return random.Next(min, max);
    }

问题是我运行了100多次,当我的min = 0和max = 1时,它总是给我相同的答案。我每次都得到0。 (我创建了一个测试函数来运行它 - 真的 - 我每次都得到0)。我很难相信这是巧合...我还能做些什么来检查或测试这个? (我用min = 0和max = 10重复测试,前50次,结果总是“5”,第二次50次,结果总是“9”。

??我需要一些更随意的东西......

-Adeena

13 个答案:

答案 0 :(得分:47)

min = 0和max = 1的问题是min是包含的,max是独占的。因此,该组合唯一可能的值是0。

答案 1 :(得分:32)

random = new Random();

这将启动具有当前时间(以秒为单位)的随机数生成器。在系统时钟更改之前多次调用函数时,随机数生成器将以相同的值启动,因此它返回相同的值序列。

答案 2 :(得分:18)

不要为Next创建包装器方法。它浪费了创建Random类的新实例的循环。只需使用同一个!

Random myRand = new Random();

for(int i = 0; i < 10; i++)
{
    Console.WriteLine(myRand.Next(0, 10).ToString());
}

这应该给你十个随机值。

如前所述 - Random是伪随机的(如同所有实现一样),如果您使用相同的种子创建100个实例,您将获得100个相同结果的实例。确保你重复上课。

此外,正如人们所说,请注意MinValue是包容性的,MaxValue是独占的。为了你想要的,做myRand.Next(0,2)。

答案 3 :(得分:7)

Next()的重载返回:

  

大于或等于minValue且小于maxValue的32位有符号整数;也就是说,返回值的范围包括minValue但不包括MaxValue。如果minValue等于maxValue,则返回minValue。

0是唯一可能返回的值。也许你想要random.NextDouble(),它将返回0到1之间的双倍。

答案 4 :(得分:6)

min是包容性的,但最大值是独占的。 Check out the API

答案 5 :(得分:6)

你总是得到0,因为Random.Next返回整数。你需要调用Random.NextDouble,它将返回0到1之间的数字。另外,你应该重用你的Random实例,如下所示:

[ThreadStatic]
static Random random;
public static Random Random { 
    get {
        if (random == null) random = new Random();
        return random;
    }
}
public static int RandomInteger(int min, int max)
{
    return Random.Next(min, max);
}
public static double RandomDouble() //Between 0 and 1
{ 
    return Random.NextDouble();
} 

如果您想要加密安全的随机数,请使用RNGCryptoServiceProvider类;见this article

编辑:线程安全

答案 6 :(得分:3)

除了在其他答案中已经提到的0-1问题之外,当你正在寻找0-10范围并且连续50次获得相同的结果时,你的问题是真实的。

new Random()应该返回一个带有从计时器初始化的种子的随机数(当前秒),但显然你每秒调用50次这个代码。 MSDN建议:“为了提高性能,创建一个随机数以随时间生成许多随机数,而不是重复创建一个新的随机数来生成一个随机数。”如果您在方法之外创建一次随机生成器,那么应​​该修复“非随机性”问题以及提高性能。

如果您需要“更高质量”的伪随机数,还要考虑this post以获得比系统提供的更好的伪随机数生成器。

答案 7 :(得分:1)

正如其他人所提到的,每秒多次构建的Random使用与种子相同的秒,因此我将Random构造函数放在循环之外,并将其作为参数传递,如下所示:

public static int RandomNumber(Random random, int min, int max)
{
    return random.Next(min, max);
}

另外如其他人所说,max是独占的,所以如果你想要一个0或1,你应该使用[0,2]作为你的[min,max]或一些更大的max,然后做一个二进制AND 1。

public static int RandomOneOrZero(Random random)
{
    return random.Next(0, int.MaxValue) & 1;
}

答案 8 :(得分:1)

这是对任何答案的补充,因为这个特定问题的答案是界限应该是(0,2)而不是(0,1)。

但是,如果要使用静态包装器方法,则必须记住Random不是线程安全的,因此您需要提供自己的同步机制或提供每线程实例。这是一个很大程度上非阻塞的实现,它使用一个生成器来为每个线程生成器设定种子:

public static class ThreadSafeRandom
{
    private static readonly Random seed = new Random();

    [ThreadStatic]
    private static Random random;

    public static int Next(int min, int max)
    {
        if (random == null)
        {
            lock (seed)
            {
                random = new Random(seed.Next());
            }
        }

        return random.Next(min, max);
    }

    // etc. for other members
}

答案 9 :(得分:1)

你误解了“random.Next(min,max)”这一行。 “min”代表允许随机生成的最小数字。虽然“max”代表不允许生成的最小数字,但它不在允许绘制的最大数字的位置。所以当行是random.Next(0,1)时,你基本上只允许绘制0。

答案 10 :(得分:0)

有几张海报表示,Random()使用基于系统时钟当前秒的种子,并且在同一秒内创建的任何其他Random实例将具有相同的种子。这是不正确的。 Random的无参数构造函数的种子基于滴答计数或自启动时间以来的毫秒数。此值大多每15毫秒在大多数系统上更新,但可能因硬件和系统设置而异。

答案 11 :(得分:0)

我找到了一种非常简单但有效的方法来生成随机数,只需取当前日期时间毫秒的最后两位数字:

   int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2));
   int cnr = new Random(seed).Next(100);

很粗糙,但是有效! :-)

当然,它每100次统计生成相同的数字。或者,你可以取所有三位数或连接其他日期时间值,如秒左右。

答案 12 :(得分:-2)

VB中的

我总是从Randomize()函数开始。只需调用Randomize()然后运行随机函数。我也做了以下事情:

Function RandomInt(ByVal lower As Integer, ByVal upper As Integer) As Integer
    Return CInt(Int((upper - lower + 1) * Rnd() + lower))
End Function

希望这有帮助! :)