题 如何在C#中生成随机int数?


如何在C#中生成随机整数?


1433
2018-04-24 23:09


起源




答案:


Random 类 用于创建随机数。 (当然是伪随机的。)。

例:

Random rnd = new Random();
int month = rnd.Next(1, 13); // creates a number between 1 and 12
int dice = rnd.Next(1, 7);   // creates a number between 1 and 6
int card = rnd.Next(52);     // creates a number between 0 and 51

如果你要创建多个随机数,你应该保留 Random 实例并重用它。如果您创建新实例的时间太近,它们将生成相同系列的随机数,因为随机生成器是从系统时钟播种的。


1896
2018-04-24 23:19



评论不适用于扩展讨论;这次谈话已经开始了 转移到聊天。 - deceze♦
只需注意Unity C#用户,你必须指定“System.Random()”,因为Unity有一个“UnityEngine.Random()”冲突(注意“UnityEngine.Random()”无法生成随机号)。由于统一并不总是默认导入系统,这可能会引起一些混乱。 - Joehot200
@JuniorM:是的,你可以使它是静态的来重用它,但你必须要小心,这样你就不会从多个线程访问它,因为它不是线程安全的(正如任何没有专门设置线程安全的类一样) )。 - Guffa
另外还有一个关于保持相同“随机”实例的评论。这让我困扰了一段时间。 - AndyUK
我认为添加一个免责声明的免责声明是有用的,因为这是一个很受欢迎的问题,以防万一有人盲目地尝试使用密码学 Random... - Daniel García Rubio


每次执行新的Random()时都会初始化。这意味着在紧密循环中,您可以多次获得相同的值。您应该保留一个Random实例并继续在同一实例上使用Next。

//Function to get random number
private static readonly Random getrandom = new Random();

public static int GetRandomNumber(int min, int max)
{
    lock(getrandom) // synchronize
    {
        return getrandom.Next(min, max);
    }
}

181
2017-10-04 11:52



这不是@Guffa在6个月前的答案中所说的吗? “如果你创建新实例的时间太近,它们将生成相同系列的随机数” - Chris
@Chris-你说得对。在此我已经提供了实现。我认为这是一个很好的方式。它效果更好。 - Pankaj Mishra
这是一个实现,它使用于seval线程的代码同步。这对于多线程应用程序来说是好事,但对单线程应用程序来说是浪费时间。 - Guffa
如果您使用该代码,您可以获得锁定护送... - Offler
@testing:我同意Pankaj的方法是正确的方法。我所说的是它可以简化为://函数获取随机数私有静态只读随机getrandom = new Random(); public static int GetRandomNumber(int min,int max){lock(getrandom){// synchronize return getrandom.Next(min,max); }} - Sean Worle


问题看起来很简单,但答案有点复杂。如果你看到几乎每个人都建议使用Random类,有些人建议使用RNG加密类。但是什么时候选择什么。

为此,我们首先需要理解“随机性”一词及其背后的哲学。

我鼓励你观看这段视频,该视频深入探讨了使用C#的RANDOMNESS哲学 https://www.youtube.com/watch?v=tCYxc-2-3fY 

首先让我们了解RANDOMNESS的哲学。当我们告诉一个人在RED,GREEN和YELLOW之间做出选择时会发生什么。是什么让一个人选择RED或YELLOW或GREEN?

c# Random

一些最初的想法进入决定他选择的人的心灵,它可以是喜欢的颜色,幸运的颜色等。换句话说,我们在RANDOM中称为SEED的初始触发器。这个SEED是起点,触发器促使他选择RANDOM值。

现在,如果SEED很容易被猜测,那么这些随机数被称为  当种子难以猜测时,这些随机数被称为 SECURED 随机数。

例如,一个人根据天气和声音组合选择颜色,那么很难猜测初始种子。

c# Random

现在让我作一个重要的声明: -

*“Random”类仅生成PSEUDO随机数并生成SECURE随机数,我们需要使用“RNGCryptoServiceProvider”类。

c# Random

随机类从您的CPU时钟获取种子值,这是非常可预测的。所以换句话说,RANDOM类的C#生成伪随机数,下面是相同的代码。

Random rnd= new Random();
int rndnumber = rnd.Next()

而RNGCryptoServiceProvider类使用OS熵来生成种子。 OS熵是一个随机值,它是使用声音,鼠标点击和键盘时序,热温等生成的。下面是相同的代码。

using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider()) 
{ 
  byte[] rno = new byte[5];    
  rg.GetBytes(rno);    
  int randomvalue = BitConverter.ToInt32(rno, 0); 
}

要了解操作系统熵,请参阅此视频 https://www.youtube.com/watch?v=tCYxc-2-3fY   从11:20开始,解释了OS熵的逻辑。因此,使用简单的单词RNG Crypto会生成SECURE随机数。


152
2018-06-14 06:27



不应该只是你的字节[5] [4]因为ToInt32只解析4个字节? - Bernhard
想想我读完毕业后从随机大学毕业 - markthewizard1234
不应该是rg.GetBytes()?而不是? - Gaspa79
@ Gaspa79:是的,应该是。我编辑了答案。 - zx485
我随机地回答了这个问题,并且在随意的情况下得到了启发。 - Vikram Kumar


要小心 new Random() 在当前时间戳上播种。

如果你想生成 只是一个数字您可以使用:

new Random().Next( int.MinValue, int.MaxValue )

有关更多信息,请查看 随机 上课,但请注意:

但是,由于时钟具有有限的分辨率,使用无参数构造函数以紧密连续的方式创建不同的随机对象会创建随机数生成器,从而生成相同的随机数序列

所以不要使用此代码生成一系列随机数。


73
2018-04-24 23:10



-1:默认种子基于时间;在循环中执行此操作,您将获得非常随机的结果。你应该创造 一 生成器并将其用于所有数字,而不是每次都使用单独的生成器。 - Bevan
嘿,那太不公平了。问题是如何生成随机int数。没有提到循环或系列。 - Fyodor Soikin
好的,公平的。撤销。虽然,我仍然认为不使用 new Random() 在循环中是一个重点。 - Bevan
(int.MaxValue + 1)溢出 - carson
谢谢@carson,有人补充说 +1 因为答案最初是写的。 - Fyodor Soikin


Random r = new Random();
int n = r.Next();

42
2018-04-24 23:10





我想添加一个加密安全版本:

RNGCryptoServiceProvider类(MSDN 要么 dotnetperls

它实现了IDisposable。

using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
   byte[] randomNumber = new byte[4];//4 for int32
   rng.GetBytes(randomNumber);
   int value = BitConverter.ToInt32(randomNumber, 0);
}

22
2017-12-18 21:02





最好用当前的毫秒为Random对象播种,以确保真正的随机数,并且你几乎不会多次使用它找到重复项

Random rand = new Random(DateTime.Now.Millisecond);

13
2017-11-01 12:30



new Random() 使用当前刻度作为种子。当您在相同的毫秒内实例化多个实例(而不是勾选)时,您将获得返回的相同值。 - Hans Kesting


你可以使用Jon Skeet的 StaticRandom 他为伪随机数构建的MiscUtil类库中的方法。

using System;
using MiscUtil;

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine(StaticRandom.Next());
        }
    }
}

12
2018-04-24 23:31



“真的随意”?这是如何运作的? - Andreas Rejbrand
我刚看了一下源代码,这个函数使用完全相同的随机数引擎,C#中的“包含”引擎,但确保所有调用使用相同的“种子”/“母对象”。 (对不起,我不知道C#术语。但我的观点是,这个函数没有比标准函数更好的随机数。) - Andreas Rejbrand
任何事物都不可能是“真正随机的”,因为总有一些限制因素或偏见包含在其存在中所固有的。你没有在科学课上听老师讲课吗? ;-) - Phill Healey
让我们说,据他说,这是“真正随机”的 - The Mitra Boy


我已经尝试了所有这些解决方案,不包括COBOL答案...大声笑

这些解决方案都不够好。我需要在快速的int循环中使用random,即使在很宽的范围内,我也会获得大量的重复值。在解决了一段随机结果后,我决定一劳永逸地解决这个问题。

这都是关于种子的。

我通过解析Guid中的非数字来创建一个随机整数,然后我用它来实例化我的Random类。

public int GenerateRandom(int min, int max)
{
    var seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
    return new Random(seed).Next(min, max);
}

更新:如果您实例化一次Random类,则无需播种。所以最好创建一个静态类并调用一个方法。

public static class IntUtil
{
   private static Random random;

   private static void Init()
   {
      if (random == null) random = new Random();
   }

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

然后你就可以像这样使用静态类了。

for(var i = 0; i < 1000; i++)
{
   int randomNumber = IntUtil.Random(1,100);
   Console.WriteLine(randomNumber); 
}

我承认我更喜欢这种方法。


10
2018-05-19 21:19



Guid不是随机的,它不是一个好种子。 GUID不保证随机性,它保证了唯一性。 stackoverflow.com/questions/2621563/... - Magu
Guid是一个好种子。我只使用Guid中的数字。亲自尝试一下这个方法。把它放在一个很长的循环中,然后自己查看结果。 - Proximo
嗯,在第二个想法..种子根本没有必要。更新答案 - Proximo
更新的重点。我甚至没想过把它变成一个静态场,这种方式效果更好,更清洁。 - JCisar
这个答案有一些问题。首先,GUID不是一个伟大的种子来源 - 仅仅因为它看起来是随机的并不意味着它。它 可能 足以满足您的个人需求。其次,Random类不是线程安全的。您需要为每个线程实例化一次。 - Hector