如何生成随机整数?


1918

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

Answers:


2501

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实例并重新使用它。如果创建的新实例在时间上过于接近,则它们将产生与从系统时钟中植入随机生成器相同的一系列随机数。


183
只是对Unity C#用户的注释,您必须指定“ System.Random()”,因为Unity会产生冲突的“ UnityEngine.Random()”(请注意,“ UnityEngine.Random()”不能生成随机数数字)。由于默认情况下团结并不总是导入System,所以这可能会引起一些混乱。
Joehot200年

2
为了重用它,您可以在初始化代码时将rndas 声明为static和/或将其设置一次。
少年梅耶

4
@JuniorM:是的,您可以使它成为静态的来重用它,但是您必须要小心,以免因为它不是线程安全的,所以不要从多个线程访问它(这对于没有专门使线程安全的任何类来说都是常见的)。
Guffa

8
我认为添加一个免责声明是不安全的是有用的,因为这是一个很普遍的问题,以防万一有人盲目地尝试对密码进行加密Random...
DanielGarcíaRubio

1
极好的答案。有一些很好的` `增强功能''可以Random使您的随机性更强大:ericlippert.com/2019/02/04/fixing-random-part-2codeblog.jonskeet.uk/2009/11/04/revisiting -随机性
Jesse C. Slicer

280

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

为此,我们需要首先了解术语“随机性”及其背后的原理。

我鼓励您使用C#https://www.youtube.com/watch?v= tCYxc-2-3fY观看有关RANDOMNESS原理的视频。

首先,我们要了解随机性的原理。当我们告诉某人在红色,绿色和黄色之间进行选择时,内部会发生什么。是什么使人们选择红色,黄色或绿色?

C#随机

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

现在,如果易于猜测SEED,则将这些随机数称为PSEUDO,而当难以猜测种子时,将这些随机数称为 SECURED随机数。

例如,一个人选择的颜色取决于天气和声音的组合,那么很难猜出初始种子。

C#随机

现在让我发表重要的声明:

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

C#随机

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

**注意:** .NET Core 2.0.0+在无参数构造函数上使用其他种子:它使用而不是CPU时钟Guid.NewGuid().GetHashCode()

var random = new Random();
int randomnumber = random.Next()

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

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

要了解OS熵,请观看14:30 https://www.youtube.com/watch?v=tCYxc-2-3fY上的这段视频,其中解释了OS熵的逻辑。因此,简单来说,RNG Crypto会生成SECURE随机数。


9
不应该是您的字节[5] [4],因为ToInt32仅解析4个字节吗?
伯恩哈德

6
了解这些课程的住处总是有帮助的。System.Security.Cryptography
Elton

1
由于并非在所有平台上都可用,因此建议使用RandomNumberGenerator.Create()而不是调用的构造函数RNGCryptoServiceProvider
dzitkowskik

我只想精确说明一下SecureRandom IS伪随机生成。
Néménor

由于种子的随机性增加,是否可以在每次需要生成随机数时创建新的RNGCryptoServiceProvider对象,还是最好还是创建一个RNGCryptoServiceProvider对象并在需要生成随机数时重用它,例如应该与Random类一起完成?
user2150989

231

每次执行new 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);
    }
}

3
这不是@Guffa在6个月前的回答中所说的吗?“如果创建的新实例在时间上过于接近,它们将产生相同的随机数序列”
克里斯,2010年

3
@克里斯-你说的对。在此,我提供了该程序的实现。我认为这是一个很好的方法。效果更好。
Pankaj Mishra 2010年

22
这是一个同步代码的实现,可用于seval线程。这对于多线程应用程序是好的,但是对于单线程应用程序来说则浪费时间。
Guffa

@SeanWorle:首先,我尝试使用Guffa的方法。然后,我尝试存储相同的Random对象。在这两种情况下,我都有相同的随机数。借助Pankaj的方法,这没有发生。也许这是随机的,但我现在对此表示怀疑。我正在从不同的线程查询同一秒的随机数。
测试

1
@testing:我同意Pankaj的方法是正确的方法。我的意思是可以简化为://获取随机数的函数私有静态只读Random getrandom = new Random(); public static int GetRandomNumber(int min,int max){lock(getrandom){//同步返回getrandom.Next(min,max); }
肖恩·沃勒

92

注意new Random()当前时间戳上的种子。

如果只想生成一个数字,则可以使用:

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

有关更多信息,请查看Random类,但请注意:

但是,由于时钟具有有限的分辨率,因此使用无参数构造函数连续创建不同的Random对象会创建随机数生成器,该生成器会生成相同的随机数序列

因此,请勿使用此代码生成一系列随机数。


41
-1:默认种子是基于时间的;循环执行此操作,您将获得非常非随机的结果。您应该创建一个生成器并将其用于所有数字,而不是每次都使用一个单独的生成器。
贝文

21
嘿,那不公平。问题是如何生成随机的int数。没有提到循环或系列。
Fyodor Soikin 2010年

26
好的,很公平。已废止。虽然,我仍然认为不new Random()循环使用是重要的一点。
Bevan 2010年

对于将来遇到这种情况的人,现在应该很明显,但是我只是指出这一点。答案已更新至此,不要在循环中将其用于多个值。
vapcguy


30

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

RNGCryptoServiceProvider类(MSDNdotnetperls

它实现IDisposable。

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

15

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

using MiscUtil;
...

for (int i = 0; i < 100; 
    Console.WriteLine(StaticRandom.Next());

31
我只是看了一下源代码,此函数使用完全相同的随机数引擎,即C#中的一个“包含”引擎,但要确保所有调用都使用相同的“种子” /“母对象”。(很抱歉,我不了解C#术语。但是,我的意思是,该函数没有比标准函数更好的随机数。)
Andreas Rejbrand 2010年

5
任何事情都不可能是“真正随机的”,因为总会存在某些限制因素或偏见,而这正是其存在所固有的。你没听科学课的老师吗?;-)
Phill Healey 2014年

假设根据他的说法,这是“真正随机的”
Mitra Boy 2015年

现在链接已断开。这就是为什么您将答案中包含的信息包括在内的原因。
vapcguy

13

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

这些解决方案都不够好。我需要快速进行int循环的随机处理,即使在很宽的范围内,我也得到大量重复值。在为某种随机结果解决了太长时间之后,我决定最终一劳永逸地解决这个问题。

都是关于种子的。

我通过解析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); 
}

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


6
引导不是随机的,它不是好的种子。GUID不能保证随机性,它可以保证唯一性。stackoverflow.com/questions/2621563/...
麻姑

2
Guid是个好种子。我只使用Guid中的数字。自己尝试该方法。将其放在一个很长的for循环中,然后亲自查看结果。
Proximo 2015年

1
嗯,再三考虑。.种子根本没有必要。更新答案
Proximo 2015年

1
关于更新的重点。我什至没有想到要使其成为静态场,这种方式效果更好而且更清洁。
JCisar

1
这个答案有一些问题。首先,GUID并不是很好的种子来源-仅因为它看起来是随机的,并不意味着它是种子。它可能足以满足您的个人需求。其次,Random类不是线程安全的。您需要每个线程实例化一次。
Hector

11

内置Random类(System.Random)生成的数字生成伪随机数。

如果您想要真正的随机数,我们可以得到的最接近的是“安全伪随机生成器”,可以通过使用C#中的Cryptographic类(例如)来生成RNGCryptoServiceProvider

即使这样,如果仍然需要真正的随机数,则将需要使用外部源(例如将放射性衰变考虑在内的设备)作为随机数生成器的种子。根据定义,由于纯粹由算法手段生成的任何数字都不能真正地是随机的。


11

创建一个随机对象

Random rand = new Random();

并使用它

int randomNumber = rand.Next(min, max);

您不必new Random()每次都需要一个随机数时进行初始化,可以启动一个随机数,然后在循环内或其他任意次数使用它


5
new Random()使用当前的刻度作为种子。当您在同一毫秒内实例化多个实例(而不是滴答声)时,您将获得返回的相同值。
汉斯·基辛

10
这是积极的坏处。DateTime.Now.Millisecond(与DateTime.Now.Ticks不同)是介于0到999之间的数字。如果为每个随机数创建一个新的数字,则只有1000种可能性。
奥伦·梅尔泽

投票赞成这个答案的24个人在想什么...?

10

这里修改答案。

如果您有权访问兼容Intel Secure Key的CPU,则可以使用以下库生成实际的随机数和字符串:https : //github.com/JebteK/RdRandhttps://www.rdrand.com/

只需从此处下载最新版本,包括Jebtek.RdRand并为其添加using语句即可。然后,您需要做的就是:

// Check to see if this is a compatible CPU
bool isAvailable = RdRandom.GeneratorAvailable();

// Generate 10 random characters
string key       = RdRandom.GenerateKey(10);

 // Generate 64 random characters, useful for API keys 
string apiKey    = RdRandom.GenerateAPIKey();

// Generate an array of 10 random bytes
byte[] b         = RdRandom.GenerateBytes(10);

// Generate a random unsigned int
uint i           = RdRandom.GenerateUnsignedInt();

如果没有兼容的CPU来执行代码,只需使用rdrand.com上的RESTful服务即可。使用项目中包含的RdRandom包装器库,您只需要这样做(注册时可获得1000个免费呼叫):

string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret   = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");

7

我在下面的代码中使用了一个随机数(不建议使用):

var random = new Random((int)DateTime.Now.Ticks);
var randomValue = random.Next(startValue, endValue + 1);

4

没关系的时候:

Random random = new Random();
int randomNumber = random.Next()

您通常希望控制限制(最小和最大木材)。因此,您需要指定随机数的开始和结束位置。

Next()方法接受两个参数min和max。

因此,如果我希望我的随机数介于5到15之间,

int randomNumber = random.Next(5, 16)

4

这是我使用的课程。像RandomNumber.GenerateRandom(1, 666)

internal static class RandomNumber
{
    private static Random r = new Random();
    private static object l = new object();
    private static Random globalRandom = new Random();
    [ThreadStatic]
    private static Random localRandom;
    public static int GenerateNewRandom(int min, int max)
    {
        return new Random().Next(min, max);
    }
    public static int GenerateLockedRandom(int min, int max)
    {
        int result;
        lock (RandomNumber.l)
        {
            result = RandomNumber.r.Next(min, max);
        }
        return result;
    }
    public static int GenerateRandom(int min, int max)
    {
        Random random = RandomNumber.localRandom;
        if (random == null)
        {
            int seed;
            lock (RandomNumber.globalRandom)
            {
                seed = RandomNumber.globalRandom.Next();
            }
            random = (RandomNumber.localRandom = new Random(seed));
        }
        return random.Next(min, max);
    }
}

您的GenerateRandom类将永远不会返回数字666,而只会返回665。这是Random.Next最大值的常见误解(功能)。
戈登·贝尔

3

我想演示每次使用一个新的随机数生成器时会发生什么。假设您有两个方法或两个类,每个都需要一个随机数。天真地将它们编码为:

public class A
{
    public A()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}

您认为您会得到两个不同的ID吗?

class Program
{
    static void Main(string[] args)
    {
        A a=new A();
        B b=new B();

        int ida=a.ID, idb=b.ID;
        // ida = 1452879101
        // idb = 1452879101
    }
}

解决方案是始终使用单个静态随机生成器。像这样:

public static class Utils
{
    public static readonly Random random=new Random();
}

public class A
{
    public A()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}

那您如何安全地选择种子?
2016年

好吧,首先,如果您创建的对象相隔10毫秒,则默认种子将生成不同的随机数。其次,您可以混搭任何随机的环境或过程数据以获取种子。然后要权衡一下,是要一个很长的数字序列(很可能会开始重复自己),还是要多个流,即使两个流最终是相同的也是如此。而且,如果您担心安全性,RNGCryptoServiceProvider还是更好的选择。
米莉·史密斯

拥有一个带有小的α粒子放射源和一个探测器(烟雾探测器的工作原理)的随机发生器芯片,以便根据放射性衰变(非常随机)对数字进行随机化,将是很酷的。
ja72 2016年

3

对于强随机种子,我始终使用CryptoRNG而不是Time。

using System;
using System.Security.Cryptography;

public class Program
{
    public static void Main()
    {
        var random = new Random(GetSeed());
        Console.WriteLine(random.Next());
    }

    public static int GetSeed() 
    {
        using (var rng = new RNGCryptoServiceProvider())
        {
            var intBytes = new byte[4];
            rng.GetBytes(intBytes);
            return BitConverter.ToInt32(intBytes, 0);
        }
    }
}

3
Random random = new Random ();
int randomNumber = random.Next (lowerBound,upperBound);

1
尽管此代码可以回答问题,但最好说明如何解决问题并提供示例或参考代码。仅代码的答案可能会造成混乱,并且缺乏上下文。
罗伯特·哥伦比亚

3

只是作为注释,以供将来参考。

如果您使用的是.NET Core,则多个Random实例并不像以前那样危险。我知道这个问题是2010年提出的,但是由于这个问题年代久远但具有一定吸引力,因此我认为记录这一变化是一件好事。

您可以参考我前一段时间提出的这个问题:

Microsoft是否更改了随机默认种子?

基本上,他们已将默认种子从更改Environment.TickCountGuid.NewGuid().GetHashCode(),因此,如果您创建2个Random实例,它将不会显示相同的数字。

您可以在此处查看来自.NET Framework / .NET Core(2.0.0+)的文件差异: https //github.com/dotnet/coreclr/pull/2192/commits/9f6a0b675e5ac0065a268554de49162c539ff66d

它不如RNGCryptoServiceProvider安全,但至少不会给您带来奇怪的结果。


现在已经过时了。反对使用Guid有很大的反对。现在的代码Interop.GetRandomBytes((byte*)&result, sizeof(int));

2

根据定义,计算机通过确定性过程计算出的数字不能是随机的。

如果您想要一个真正的随机数,则随机性来自大气噪声或放射性衰变。

您可以尝试例如RANDOM.ORG(它会降低性能)


2
Random rand = new Random();
int name = rand.Next()

将所需的任何值放在第二个括号中,以确保通过编写prop和double选项卡生成代码来设置名称


1
道具和双标签?
DCShannon 2014年

为什么要使用prop和double tab?您是在说没有该属性的简写的键盘快捷键,您的代码将无法工作?
Sнаđошƒаӽ

2

如果您希望CSRNG生成介于最小值和最大值之间的随机数,那么这是给您的。它将Random使用安全的随机种子初始化类。

    class SecureRandom : Random
    {
        public static byte[] GetBytes(ulong length)
        {
            RNGCryptoServiceProvider RNG = new RNGCryptoServiceProvider();
            byte[] bytes = new byte[length];
            RNG.GetBytes(bytes);
            RNG.Dispose();
            return bytes;
        }
        public SecureRandom() : base(BitConverter.ToInt32(GetBytes(4), 0))
        {

        }
        public int GetRandomInt(int min, int max)
        {
            int treashold = max - min;
            if(treashold != Math.Abs(treashold))
            {
                throw new ArithmeticException("The minimum value can't exceed the maximum value!");
            }
            if (treashold == 0)
            {
                throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
            }
            return min + (Next() % treashold);
        }
        public static int GetRandomIntStatic(int min, int max)
        {
            int treashold = max - min;
            if (treashold != Math.Abs(treashold))
            {
                throw new ArithmeticException("The minimum value can't exceed the maximum value!");
            }
            if(treashold == 0)
            {
                throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
            }
            return min + (BitConverter.ToInt32(GetBytes(4), 0) % treashold);
        }
    }

1

抱歉,OP确实需要一个随机int值,但是出于共享知识的简单目的,如果您想要一个随机BigInteger值,可以使用以下语句:

BigInteger randomVal = BigInteger.Abs(BigInteger.Parse(Guid.NewGuid().ToString().Replace("-",""), NumberStyles.AllowHexSpecifier));

0

我将假设您想要一个均匀分布的随机数生成器,如下所示。大多数编程语言(包括C#和C ++)中的随机数在使用它们之前均未正确混洗。这意味着您将一遍又一遍地得到相同的数字,这并不是真正随机的。为了避免一遍又一遍地绘制相同的数字,您需要一个种子。通常,此任务的时间间隔是可以的。请记住,如果每次使用相同的种子,您将一遍又一遍地获得相同的数字。因此,请始终尝试使用变化的种子。时间是种籽的好来源,因为它们总是不断变化。

int GetRandomNumber(int min, int max)
{
    Random rand = new Random((int)DateTime.Now.Ticks);
    return rand.Next(min, max);
}

如果您正在寻找用于正态分布的随机数生成器,则可以使用Box-Muller变换。检查随机高斯变量问题中yoyoyoyosef的答案。由于需要整数,因此必须在末尾将双精度值转换为整数。

Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
         Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
         mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)

随机高斯变量


0

最简单的方法可能就是Random.range(1, 3)生成1到2之间的数字。



-2

为什么不使用int randomNumber = Random.Range(start_range, end_range)


实际上是int randomNumber = Random.Range(start_range,end_range + 1)
Gordon Bell

3
是否存在Random.Range()?我在MSDN文档中找不到它。
菲利普·恩甘

我也没有在MSDN文档中找到Random.Range()
user2455111

-2

重复使用一个随机实例

// Somewhat better code...
Random rng = new Random();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(GenerateDigit(rng));
}
...
static int GenerateDigit(Random rng)
{
    // Assume there'd be more logic here really
    return rng.Next(10);
}

本文探讨了为什么随机性会导致如此多的问题,以及如何解决这些问题。 http://csharpindepth.com/Articles/Chapter12/Random.aspx


Random不是线程安全类。如果创建单个实例,则应在锁定机制之后限制对其的访问。
Brad M

-2

请尝试以下简单步骤来创建随机数:

创建函数:

private int randomnumber(int min, int max)
{
    Random rnum = new Random();
    return rnum.Next(min, max);
}

在要使用随机数的位置使用上述功能。假设您要在文本框中使用它。

textBox1.Text = randomnumber(0, 999).ToString();

最小值为0,最大值为999。您可以将值更改为所需的任何值。


当紧密联系在一起多次时,它将返回相同的数字,因为它使用系统时间作为种子...
MOnsDaR 2016年

1
randomnumber(0,999)永远不会返回999。最大值不包括在内。这是Random.Next最大值的常见误解(特征)。
戈登·贝尔

-2

我总是有生成随机数的方法,这些方法可用于各种目的。我希望这对您也有帮助:

public class RandomGenerator  
{  
    public int RandomNumber(int min, int max)  
    {  
        var random = new Random();  
        return random.Next(min, max);  
    }  

    public string RandomString(int size, bool lowerCase)  
    {  
        var builder = new StringBuilder();  
        var random  = new Random();  
        char ch;  

        for (int i = 0; i < size; i++)  
        {  
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));  
            builder.Append(ch);  
        }  

        if (lowerCase)  
            return builder.ToString().ToLower();  
        return builder.ToString();  
    }  
}

-3

内联快速简便,请使用以下代码:

new Random().Next(min, max);

// for example unique name
strName += "_" + new Random().Next(100, 999);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.