关于C#:如何生成一个随机整数?

 2019-04-22 

How do I generate a random int number?

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


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

例子:

1
2
3
4
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实例并重用它。如果创建的新实例时间太近,它们将生成与从系统时钟中种子生成的随机生成器相同的一系列随机数。


每次执行新的random()时,它都会被初始化。这意味着在一个紧密的循环中,你会多次得到相同的值。您应该保留一个随机实例,并在同一个实例上继续使用next。

1
2
3
4
5
6
7
8
9
10
//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);
    }
}


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

为此,我们需要首先理解"随机性"这个术语及其背后的哲学。

我鼓励你观看这段视频,它深入了解随机性的原理,使用c https://www.youtube.com/watch?V= TCYXC-2-3FY

首先让我们理解随机性的哲学。当我们告诉一个人在红色、绿色和黄色之间做出选择时,内部会发生什么。是什么让一个人选择红色、黄色或绿色?

c# Random

一些最初的想法进入了决定他选择的人的头脑,它可以是最喜欢的颜色,幸运的颜色等等。换句话说,我们随机称之为种子的初始触发器。这个种子是开始点,是促使他选择随机值的触发器。

如果一个种子很容易猜测,那么这些随机数就称为伪随机数,当一个种子很难猜测时,这些随机数就称为安全随机数。

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

c# Random

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

*"random"类只生成伪随机数,要生成安全随机数,我们需要使用"rngcryptoServiceProvider"类。

c# Random

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

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

而rngCryptoServiceProvider类使用操作系统熵来生成种子。操作系统熵是一个随机值,它是由声音、鼠标点击和键盘计时、热温度等产生的。下面的代码是相同的。

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

要了解操作系统熵,请看14:30的视频https://www.youtube.com/watch?v=tcyxc-2-3fy,其中解释了操作系统熵的逻辑。因此,输入简单的单词rng crypto会生成安全的随机数。


注意,new Random()是在当前时间戳上播种的。

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

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

有关更多信息,请查看随机类,不过请注意:

However, because the clock has finite resolution, using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers

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


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

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

RNGCryptoServiceProvider类(msdn或dotnetperls)

它实现IDisposable。

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

你可以在他为伪随机数构建的miscutil类库中使用jon skeet的staticrandom方法。

1
2
3
4
5
using MiscUtil;
...

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


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

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

更新

我知道new Random()使用当前的滴答作为种子,但是用当前毫秒播种仍然足够好,因为它是一个很好的随机启动

最后一点是,您不必每次需要一个随机数时都初始化new Random(),启动一个随机对象,然后在一个循环内或其他任何情况下根据需要多次使用它。


我尝试过所有这些解决方案,除了COBOL的答案…大声笑

这些解决方案都不够好。我需要一个快速的randoms for int循环,即使在非常宽的范围内,我也得到了大量的重复值。在解决了太长时间的随机结果之后,我最终决定一次性解决这个问题。

一切都是为了种子。

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

1
2
3
4
5
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);
}

更新:如果将随机类实例化一次,则不需要进行种子设定。所以最好创建一个静态类并调用一个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
   }
}

然后您可以像这样使用静态类。

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

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


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

如果您想要真正的随机数,我们能得到的最接近的是"安全伪随机生成器",它可以通过使用C中的加密类(如RNGCryptoServiceProvider)生成。

即使如此,如果你仍然需要真正的随机数,你将需要使用一个外部的来源,如计算放射性衰变的设备作为随机数生成器的种子。因为,根据定义,任何由纯算法方法生成的数字都不能是真正随机的。


我用下面的代码有一个随机数:

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

从这里修改了答案。

如果您可以访问与Intel Secure Key兼容的CPU,则可以使用以下库生成真正的随机数和字符串:https://github.com/jebtek/rdrand和https://www.rdrand.com/

从这里下载最新版本,包括jebtek.rdrand并为其添加一个using语句。那么,你需要做的就是:

1
2
3
4
5
bool isAvailable = RdRandom.GeneratorAvailable();  // Check to see if this is a compatible CPU
string key       = RdRandom.GenerateKey(10);       // Generate 10 random characters
string apiKey    = RdRandom.GenerateAPIKey();      // Generate 64 random characters, useful for API keys
byte[] b         = RdRandom.GenerateBytes(10);     // Generate an array of 10 random bytes
uint i           = RdRandom.GenerateUnsignedInt()  // Generate a random unsigned int

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
    }
}


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


当一切正常时:

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

大多数情况下你都想控制极限(最小和最大)。所以您需要指定随机数的起始和结束位置。

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

所以如果我想让我的随机数在5到15之间,我就这么做

1
int randomNumber = random.Next(5, 16)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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; }
}

你认为你会得到两个不同的身份证吗?不

1
2
3
4
5
6
7
8
9
10
11
12
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
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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; }
}


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

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

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


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

在第二个圆括号中放入您想要的任何值确保通过编写prop和double tab来设置名称以生成代码


对于强随机种子,我总是使用密码学而不是时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
        }
    }
}


您可以尝试使用以下随机种子值:

1
2
3
4
5
var rnd = new Random(11111111); //note: seed value is 11111111

string randomDigits = rnd.Next();

var requestNumber = $"SD-{randomDigits}";


我假设您需要一个如下的均匀分布随机数生成器。包括C语言和C++的大多数编程语言中的随机数在使用它们之前都没有被正确地洗牌。这意味着你将得到相同的数字,一次又一次,这不是真正随机的。为了避免一次又一次地绘制相同的数字,您需要一个种子。通常,此任务的时间刻度是可以的。记住,如果每次使用相同的种子,您将得到相同的数字。所以试着用不同的种子。时间是种子的好来源,因为它们总是痛苦的。

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

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

1
2
3
4
5
6
7
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)

随机高斯变量


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

创建函数:

1
2
3
4
5
private int randomnumber(int min, int max)
{
    Random rnum = new Random();
    return rnum.Next(min, max);
}

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

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

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


对不起,op确实需要一个随机的int值,但是为了简单的分享知识,如果你想要一个随机的BigInteger值,你可以使用以下语句:

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

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


快速方便的内联,使用以下代码:

1
2
3
4
new Random().Next(min, max);

// for example unique name
strName +="_" + new Random().Next(100, 999);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();  
    }  
}

重复使用一个随机实例

1
2
3
4
5
6
7
8
9
10
11
12
// 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


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

您还可以为Next()函数提供最小值和最大值。像:

1
 int n = new Random().Next(5, 10);