Random.Next总是返回相同的值

3

我使用一种生成唯一数字的方法,但总是得到相同的数字-2147483648。即使我停止程序,重新编译并再次运行,我仍然会看到相同的数字。

  public static int GetRandomInt(int length)
    {           
        var min = Math.Pow(10, length - 1);
        var max = Math.Pow(10, length) - 1;
        var random = new Random();
        return random.Next((int)min, (int)max);
    }

这篇文章已经被讨论了数百次。来自stackoverflow的常见问题解答 - Mikant
我认为你可能有一个截断错误。-2147483648是最小的可能整数。 - amccormack
5
这不是一个重复的问题,问题的性质是不同的。 - mmix
8个回答

7
尝试将随机实例外部化:
private readonly Random _random = new Random();

public static int GetRandomInt(int length)
{           
    var min = Math.Pow(10, length - 1);
    var max = Math.Pow(10, length) - 1;
    return _random.Next((int)min, (int)max);
}

随机数生成器默认使用时间作为种子,这有什么好处呢? - LiamB
1
@Pino,是的,但如果您在循环中调用此方法,则可能会使用相同的值对随机生成器进行种子处理。将Random变量外部化可确保仅对其进行一次种子处理,并且每次调用.Next时都会获得一个随机数。 - Darin Dimitrov
@Pino:看我的回答。如果不每次创建新的Random实例,你就允许RNG序列前进并实际返回其伪随机值。如果每次重新初始化(重新播种)它,你将得到相同的结果,直到系统时钟推进。(E:太慢了 :)) - SirViver
2
@SirViver @Darin,但是OP说他重新编译后得到了相同的数字。这不会消除他使用相同时间种子的可能性吗? - amccormack

3

这不是不重用随机实例的问题,他得到的结果应该在多次启动时是随机的,而不总是-(2^32)。

问题在于长度太大,并将长度的幂转换为int类型。如果你将代码分成以下几行:

        var min = Math.Pow(10, length - 1);
        var max = Math.Pow(10, length) - 1;
        var random = new Random();
        var a = (int)min;
        var b = (int)max;
        return random.Next(a, b);

你会发现a和b都是-2147483648,这是Next(min, max)的唯一可能结果(文档规定如果min==max,则返回min)。
使用此方法可以安全地使用的最大长度为9。长度为10时将会出现System.ArgumentOutOfRangeException,长度大于10时将得到-2147483648的结果。

没错,就是这个溢出问题和实例的事情。 - H H
你没有依据在这个问题上做出那样的断言,他可能只是偶尔执行此操作,这种情况下保留一个活动的随机实例实际上是一种不好的做法。我简直不敢相信你们都关闭了这个问题。你们有没有读过它? - mmix
是的,这有点仓促。但是重复的问题每周都会出现几次。原帖作者应该更好地解释范围的事情。 - H H
2
以我的看法,楼主可能不知道他有一个范围问题,也许是初学者。在我看来,这个话题正在发生的事情非常说明在像c#和linq这样的高流量标签中SO盲目竞争的情况。这一切都只是关于积分,很少有人关心其他事情,显然包括资深成员。你甚至意识到最高排名的答案在这里甚至无法编译,因为它引用静态方法的实例字段吗?重复的问题出现并不是虐待这个问题的借口。 SO跳了鲨鱼吗? - mmix

2

您应该保留一个Random实例,而不是一直使用new()方法创建新的实例,这样会得到更好的结果。

同时要检查length的长度。因为它可能会给你一些奇怪的限制性结果。


2

您的代码存在三个问题。

  1. 您应该将随机变量外部化。
  2. 您的代码存在截断误差问题。
  3. 最小值和最大值之间的范围太大。

第一个问题是因为在重新初始化随机变量时,您可能没有足够的时间来提高种子。第二个错误是由于将(非常大的)数字截断为整数。最后,您最大的问题是最小值和最大值之间的范围。请考虑使用输入1-20定义的最小值和最大值之间的范围(如代码中所定义)。

length  max-min        
1       8
2       89
3       899
4       8999
5       89999
6       899999
7       8999999
8       89999999
9       899999999
10      8,999,999,999
11      89999999999
12      899999999999
13      8999999999999
14      89999999999999
15      899999999999999
16      9E+15
17      9E+16
18      9E+17
19      9E+18

请注意,最大整数是2,147,483,647,任何大于9的数字都将超过它。

1

我认为问题在于计算minmax。它们很快就会超过Int32.MaxValue...


0

随机类通常使用种子来初始化自己,并且如果种子相同,它们通常会返回相同的序列:

  • 总是重复使用相同的Random()实例,而不是一遍又一遍地重新创建一个
  • 如果您想要不可预测的结果,使用基于时间的种子而不是硬编码的种子

编写真正的随机数生成器非常困难。大多数方法使用外部熵发生器(例如鼠标移动、CPU温度,甚至是复杂的物理机制,例如氦气球相互碰撞...)。


0

Random实例应该只创建一次,然后重复使用。原因是RNG默认情况下以当前系统时间作为种子。如果您快速创建新的Random实例(并从中提取一个值),则其中许多实例将使用相同的时间戳进行种子处理,因为循环可能执行得比系统时钟快。

请记住,由种子A初始化的RNG将始终返回序列B。因此,如果您创建三个使用例如123作为种子的Random实例,则这三个实例在同一迭代中始终返回相同的数字。


0
在你的类中,实例化一个 Random 对象,例如:
public class MyClass
{
private readonly Random random = new Random();

public static int GetRandomInt(int length)
{
  var min = Math.Pow(10, length - 1);
  var max = Math.Pow(10, length) - 1;
  return random.Next((int)min, (int)max);
}

}

随机数总是返回相同的值,这只存在于测试目的。


使用静态变量来保存Random实例不是一个好主意 - 它不是线程安全的。 - Jon Skeet
@Jon Skeet - 你说得对!谢谢! - Christian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接