我知道这个问题已多次提出,但这些解决方案都不适用于我。
首先,我在名为RandomNumGenerator(items)
List<int> randNum = new List<int>();
foreach (var item in items)
{
randNum.Add(new Random(1000).Next());
}
这总是给了我相同的数字,然后在看this answer之后我做了这个:
Random rnd = new Random(1000);
foreach (var item in items)
{
randNum.Add(rnd.Next());
}
这给了我以下数字
325467165
506683626
1623525913
2344573
1485571032
现在虽然循环的每次迭代都没问题,但问题是,当我停止并重新运行应用程序时,我得到了我之前重新获得的相同数字。
325467165
506683626
1623525913
2344573
1485571032
仅在调试期间出现这种情况,或者每次拨打RandomNumGenerator
时都会遇到同样的问题吗?
答案 0 :(得分:155)
您总是使用相同的种子1000在Random
实例播种:
Random rnd = new Random(1000);
这不会那样做,因为当前时间用作种子:
Random rnd = new Random();
查看int
的{{3}}。
为不同的Random对象提供相同的种子值 每个实例产生相同序列的随机数。
答案 1 :(得分:41)
根据MSDN。
public Random(
int Seed
)
种子
用于计算伪随机数序列的起始值的数字。如果指定了负数,则使用该数字的绝对值。
大多数初学者涉及RNG(随机数发生器)的错误的原因是缺乏对种子&#34;种子的理解。是和它的作用。
Random
类是用于生成伪随机数的类 - 或出现的数字是随机的。它们通常是一个数学函数,它使用一个参数 - &#34;种子&#34; - 生成一系列似乎是随机的数字。
在new Random(1000)
的情况下,前5个非负随机整数是
325467165
506683626
1623525913个
2344573个
1485571032
在你的第一个代码中,每次需要一个随机数时,你都会用相同的种子创建一个新的伪随机数序列,所以显然你的数组用相同的数字填充:{{ 1}},恰好是由325467165
生成的第一个非负整数。
这也解释了为什么每次启动应用程序时,第二个代码总是生成相同的伪随机数序列。
为确保您的应用始终生成不同的伪随机序列,您每次都需要使用不同的种子。到目前为止,确保 的最简单方法是花费你的时间,字面意思。
new Random(1000)
幸运的是,你不必输入这么多,因为default constructor for the Random
class已经做了类似的事情。
Random rnd = new Random(DateTime.UtcNow.Millisecond);
// Taking the millisecond component, because it changes quickly
请注意,Random rnd = new Random(); // Much simpler, isn't it?
类不线程安全;如果多个线程同时尝试访问同一个Random
对象,则RNG将在其生命周期的剩余时间内仅返回0。
另外需要注意的是,一个接一个地创建多个Random
对象 - 即使使用时间作为种子 - 也可能导致相同的伪随机数序列。
Random
在上面的代码中,非常高,Random r1 = new Random();
Random r2 = new Random();
Random r3 = new Random();
Random r4 = new Random();
,r1
,r2
和r3
都会生成相同的序列
怎么可能?
好吧,(联合国)幸运的是,CPU正在快速发展。 1 GHz CPU每秒可执行大约10亿条指令(给予或接受);这是每1纳秒的1条指令 - 或者每1 百万分之一的指令毫秒。
创建一个新的r4
对象可能需要相当多的指令,但绝对少于而不是百万个。
因为它对于保持多个终端同步非常有用。
想象一下游戏中随机出现的重要现象,例如可能完全颠覆游戏的天气变化。你不希望只有一方遭受大雾,其余的仍然是晴朗的天气,对吗?
当然,您可以让服务器或主机生成随机天气变化并通知玩家;或者您可以在游戏开始之前定义种子,并使用该种子来确保相同的随机性&#34;在整个游戏过程中所有玩家。
不编码很有趣吗?
答案 2 :(得分:19)
你需要改变这个:
Random rnd = new Random(1000);
到
Random rnd = new Random();
默认种子值是从系统时钟派生的,并且是有限的 解析度。结果,创建了不同的Random对象 通过调用默认构造函数来关闭连续 相同的默认种子值,因此,将产生相同的 随机数集。使用单个可以避免此问题 随机对象生成所有随机数。你也可以解决 它通过修改系统时钟返回的种子值然后 明确地向Random(Int32)提供这个新的种子值 构造函数。有关更多信息,请参阅Random(Int32)构造函数。
答案 3 :(得分:5)
关键概念是随机种子 - 随机派生其他所有内容的初始数据。如果种子是相同的,那么“随机”序列将是相同的。
默认情况下,种子设置为零,这显然会导致程序运行中重复序列。
为了避免这种情况,你可以像这样构建你的随机:
Random rnd = new Random();
......在引擎盖下,是:
Random rnd = new Random(Environment.TickCount);
这将从OS启动开始以毫秒为单位初始化Random对象。每次程序启动时都会有所不同,因此每次都会得到不同的随机序列。
答案 4 :(得分:2)
Random .Next()方法生成伪随机数。您应该声明并初始化随机对象,而不是每次都创建新对象。并且不需要使用任何Cryctography .. :)
答案 5 :(得分:-1)
您应该使用班级随机变量。如果您在方法级别使用新的Random作为本地,则依赖于时间的种子将重复生成相同的随机数序列。
class Program
{
static Random _r = new Random();
static void Main()
{
// use _r variable to generate random number
}
}