Random相关的

官方释义:表示伪随机数生成器,这是一种能够产生满足某些随机性统计要求的数字序列的算法。

(1)为什么叫做“伪随机数生成器”?

Random本质上是利用一种算法,利用数学算法进行加密,从一组数中挑选出一个,但它们足够随机,可用于实际目的。(来自:微软)

实际上我们可以通过相同的数学算法对Random的结果进行预测,所以要进行加密安全,请不要使用!

①  Random下面的用法在数组当中添加随机数,只适用于byte和double两种类型

byte[] bytes1 = new byte[100];
Random rnd1 = new Random();
rnd1.NextBytes(bytes1);
for(int i = 0; i < bytes1.Length; i++)
{
   Console.WriteLine(bytes1[i]);
}

② 也可用于从string[] 中随机挑选一个,返回的是他的下标值(int)

Random rnd = new Random();
string[] malePetNames = { "Rufus", "Bear", "Dakota", "Fido",
                          "Vanya", "Samuel", "Koani", "Volodya",
                          "Prince", "Yiska" };

 
// Generate random indexes for pet names
int mIndex = rnd.Next(malePetNames.Length);
Console.WriteLine(" For a male: {0}", malePetNames[mIndex]);

③ 一般用法

Random rnd = new Random();
int str=rnd.Next(1,6);//从1到5之间随机选择一个数字
int nol=rnd.Next(6);//从0到5之间随机选择一个数字

 

注意:

使用时请不要过多的实例化Random对象,像这样(这会消耗太多的计算)

Random rnd = new Random();
int str=rnd.Next(1,6);//从1到5之间随机选择一个数字
 
 
Random nor = new Random();
int nol=nor.Next(6);//从0到5之间随机选择一个数字

在线程当中注意保护Random

如果应用从多个线程调用方法,则必须使用同步对象来确保一次只有一个线程可以访问随机 Random 数生成器。 如果不确保以线程安全的方式访问对象,则对返回随机数的方法的调用 Random 将返回 0。(微软)

请确保在使用过程中不会有多个线程同时调用此方法,让他们有序调用。

 

c#的随机数种子

先来简单的说下为什么要用随机数种子

主要的原因是希望我们随机出来的数字“尽可能的”不重复、

为什么是尽可能?

这是因为Random本质上是一种数字序列的算法,所以避免不了出现重复相同。

但为了尽量随机,让他不一致,因此使用随机数种子

random首先要考虑线程问题,因此需要使用lock锁
但如果你在unity中使用,也建议你为了线程安全使用,这并不强制,这需要您注意处理伪线程。

  Object game = new Object();//线程锁
 
            Random random = new Random((int)DateTime.Now.Ticks);//随机数
            //这里面是获取你当前的时间信息作为种子来进行随机的,要求是一个整数作为种子
            注(1)
            List<int> ints = new List<int>();//将随机出来的数字保存到集合
 
            lock (game) //加线程锁,保护线程
            {
 
               
                for (int i = 0; i < 50; i++)//随机50个对象
                {
                    int ran = random.Next(0, 100);//指定范围0——100
 
                    if (!ints.Contains(ran)) //如果在集合中没有相同的数字添加到集合中
                    {
                        ints.Add(ran);
                    }
                }
 
            }
 
            for (int i = 0; i < ints.Count; i++) //输出集合中的数字,如果你要使用的话,也可以选择前几个数字
            {
                Console.WriteLine(ints[i]);
            }
           
            
 

这里使用时间是为了让他足够随机,因为我们的时间是在不断变化的,这样确保了种子的随机性,但random选取种子会有15ms的一个随机序列生成,时间很短,这也就会导致会有一定重复的可能性

为了剔除这种随机出来相同的数字,我们将出来不同的数字添加到集合中,来以此确保它不会重复。

 

附坑:

 注意下面的 跑的结果是100个一样的值,

 

 

  static void Main(string[] args)
        {
            var list = new List<int>();
            
            for (int i = 0; i < 100; i++)
            {
                list.Add(new Random().Next(0, 50));
            }

            list.ForEach((i) =>
            {
                Console.WriteLine(i);
            });

            Console.Read();
        }

如果把 new Random()提到for循环外就不一样,或者for中加Thread.Sleep(1)也有所不同

或者 换成   list.Add(new Random().GetHashCode());  

或者 new Random(Guid.NewGuid().GetHashCode())

或者  new Random(i * 5)

 

Random.Next为什么多次New之后,会出现重复?

要想知道为什么,我们得一定要用Reflector来反编译下Random类的代码,到底里面是怎么实现的,要知

     其然,还要知其所以然,下面我们来看看反编译后的代码。

从next函数中的定义可以看出,其实return 的num值取决于seedArray,那么我们下一步看看seedArray到底是怎么玩起来的。

通过代码,我们可以找到其实就是在ctor里面做的。

我们可以看到这个for循环,大概看下代码意思,可以看出第一个for是给seedArray灌值,第二个for是取下标就是求余,然后-=操作

来让SeedArray中的值更加的混乱,反正大体意思就是SeedArray中的值比较乱,比较随机,然后我们的next就是通过inext和inextp

取SeedArray值,从而造成随机数,这个不难看出,随机的源头就是我们给过去的Seed值,然后我们看到inext和inextp都是++操作,

所以我们多次next操作之后,这就保证我们取数永远都是随机的,而如果源头的Seed一样的话,就会导致return的值一直重复。

这次我们把Random放到for循环之外再看看,因为inext和inextp是通过++操作来获取SeedArray的值来尽可能的避免重复。

 

posted @ 2022-10-23 00:02  凯帝农垦  阅读(42)  评论(0编辑  收藏  举报