[英]Why does it appear that my random number generator isn't random in C#?
我正在使用 Microsoft Visual C# 2008 Express。
我找到了这段代码:
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
min = 0和max = 1的问题是min是包含的,max是独占的。 因此,该组合的唯一可能值为0。
random = new Random();
这将启动具有当前时间(以秒为单位)的随机数生成器。 在系统时钟更改之前多次调用函数时,随机数生成器将以相同的值启动,因此它返回相同的值序列。
不要为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)。
Next()的重载返回:
大于或等于minValue且小于maxValue的32位有符号整数; 也就是说,返回值的范围包括minValue但不包括MaxValue。 如果minValue等于maxValue,则返回minValue。
0是唯一可能返回的值。 也许你想要random.NextDouble(),它将在0和1之间返回一个double。
最小值是包容性的,但最大值是独家的。 查看API
你总是得到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
类; 看到这篇文章
编辑:线程安全
你误解了“random.Next(min,max)”这一行。 “min”代表允许随机生成的最小数字。 虽然“max”代表不允许生成的最小数字,但它不在允许绘制的最大数字的位置。 所以当行是random.Next(0,1)时,你基本上只允许绘制0。
正如其他人所提到的,每秒多次构建的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,然后用1做二进制AND。
public static int RandomOneOrZero(Random random)
{
return random.Next(0, int.MaxValue) & 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
}
我找到了一种非常简单但有效的方法来生成随机数,只需取当前日期时间毫秒的后两位数:
int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2));
int cnr = new Random(seed).Next(100);
这很粗糙,但它确实有效! :-)
当然,它每100次统计生成相同的数字。 或者,你可以取所有三位数或连接其他日期时间值,如秒左右。
你的范围不正确。 minValue 包含在范围内,而 maxValue 在范围内不包含(意味着它不会包含在范围内)。 所以这就是为什么它只返回 0。
另一个有用的注意事项:在方法中创建一个 Random 实例并不理想,因为它可能在调用时获得相同的种子。 所以我会说使用:
static Random gen = new Random();
public static int RandomNumber(int minValue, int maxValue){
return gen.Next(minValue, maxValue);
}
一些海报已经声明Random()使用基于系统时钟当前秒的种子,并且在同一秒中创建的任何其他Random实例将具有相同的种子。 这是不正确的。 Random的无参数构造函数的种子基于滴答计数或自启动时间以来的毫秒数。 此值大多每15毫秒在大多数系统上更新,但可能会因硬件和系统设置而异。
在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
希望这可以帮助! :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.