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的值来尽可能的避免重复。