Unity C# 生成随机数问题
随机数问题目录
- 随机数问题简述
- 第一种方法 线性同余法求随机数
- 第二种方法 采用延迟的方法避免重复
- 第三种方法 采用数组保存索引判断是否有重复
- 第四种方法 采用Hashtable判断是否有重复值
- 第五种方法 采用递归判断是否有重复值
- 总结
随机数问题简述
此篇文章主要解决在同一时间内,多次调用
System.Random.Next() UnityEngine.Random.Range()
等使用C#语言的编译环境,产生重复值的问题(除去偶然性)
为了方便,下面代码全部可以直接复制粘贴使用
第一种方法 线性同余法求随机数
线性同余随机数生成器公式
X(n+1) = (a * X(n) + c) % m
古老的LCG(linear congruential generator)代表了最好最朴素的伪随机数产生器算法。主要原因是容易理解,容易实现,而且速度快。
其中,各系数为:
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。
一般而言,高LCG的m是2的指数次幂(一般232或者264),因为这样取模操作截断最右的32或64位就可以了。多数编译器的库中使用了该理论实现其伪随机数发生器rand()。
第N+1个数 = ( 第N个数 * A + B) % M
上面的公式中A、B和M分别为常数,是生成随机数的因子,如果之前从未通过同一个Random对象生成过随机数(也就是调用过Next方法),那么第N个随机数为将被指定为一个默认的常数,这个常数在创建一个Random类时被默认值指定,Random也提供一个构造函数允许开发者使用自己的随机数因子,这一切可通过微软官方开源代码看到:
public Random() : this(Environment.TickCount) { } public Random(int Seed) { }
为了生成更加可靠的随机数,微软在System.Security.Cryptography命名空间下提供一个名为RNGCryptoServiceProvider的类,它采用系统当前的硬件信息、进程信息、线程信息、系统启动时间和当前精确时间作为填充因子,通过更好的算法生成高质量的随机数。下面直接贴代码了:
/// <summary> /// 随机数方法 /// </summary> /// <param name="count">取随机数的个数</param> /// <param name="maxnum">随机数的最小值(包含)</param> /// <param name="minnum">随机数的最大值(包含)</param> /// <returns>结果数组</returns> public int[] RandomFunction(int count,int minnum, int maxnum) { int[] result=new int[count]; System.Random random = new System.Random(GetRandomSeed()); for (int i = 0; i < count; i++) { result[i] = random.Next(minnum, maxnum + 1); } return result; } /// <summary> /// 拿到随机种子 /// </summary> /// <returns></returns> private int GetRandomSeed() { byte[] bytes = new byte[4]; System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); rng.GetBytes(bytes); return BitConverter.ToInt32(bytes, 0); }
还有一种方法与这种类似,可以直接归类到这里
使用 System.Guid().GetHashCode() 来替换 RandomSeed
第二种方法 采用延迟的方法避免重复
这种其实没什么用,但还是列出来吧,随机数因子默认为时钟,所以等一下就好了,一般也不用这种方法
System.Random random = new System.Random(); Debug.Log(random.Next(1, 100).ToString()); Thread.Sleep(100); Debug.Log(random.Next(1, 100).ToString()); Thread.Sleep(100); Debug.Log(random.Next(1, 100).ToString());
第三种方法 采用数组保存索引判断是否有重复
思想是用一个数组来保存索引号,先随机生成一个数组位置,然后把随机抽取到的位置的索引号取出来,并把最后一个索引号复制到当前的数组位置,然后使随机数的上限减一。这样就保证了取的值一定不会是重复的,但也有个缺点
取随机数的个数一定不能大于最大值最小值的区间
/// <summary> /// 随机数方法 /// </summary> /// <param name="count">取随机数的个数</param> /// <param name="minnum">随机数的最小值(包含)</param> /// <param name="maxnum">随机数的最大值(包含)</param> /// <returns>结果数组</returns> public int[] RandomFunction(int count,int minnum, int maxnum) { //数据总量 最大值 int numCount = maxnum; //结果数量 int resCount = count; //设置下限 int site = numCount; //新建数据总量位的数组 int[] index = new int[numCount]; //分别赋值 for (int i = 0; i < numCount; i++) index[i] = i; System.Random r = new System.Random(); //用来保存随机生成的不重复的结果数量的个数 int[] result = new int[resCount]; int id; for (int j = 0; j < resCount; j++) { id = r.Next(minnum, site - 1); //在随机位置取出一个数,保存到结果数组 result[j] = index[id]; //最后一个数复制到当前位置 index[id] = index[site - 1]; //位置的下限减少一 site--; } return result; }
第四种方法 采用Hashtable判断是否有重复值
这个不用多解释,利用Hashtable对比表的值保证每个随机数只有一个
不建议大量数据使用
/// <summary> /// 随机数方法 /// </summary> /// <param name="count">取随机数的个数(不建议取过大)</param> /// <param name="minnum">最小值(包含)</param> /// <param name="maxnum">最大值(包含)</param> /// <returns>结果数组</returns> public int[] RandomFunction(int count,int minnum,int maxnum) { Hashtable hashtable = new Hashtable(); System.Random rm = new System.Random(); int RmNum = count; int[] result = new int[count]; for (int i = 0; hashtable.Count < RmNum; i++) { int nValue = rm.Next(minnum,maxnum+1); if (!hashtable.ContainsValue(nValue)) { hashtable.Add(nValue, nValue); result[i] = nValue; } } hashtable = null; return result; }
第五种方法 采用递归判断是否有重复值
用它来检测生成的随机数是否有重复,如果取出来的数字和已取得的数字有重复就重新随机获取。
不建议大量数据使用
/// <summary> /// 随机数方法 /// </summary> /// <param name="count">取随机数的个数(不要过大)</param> /// <param name="minnum">最小值(包含)</param> /// <param name="maxnum">最大值(包含)</param> /// <returns>结果数组</returns> public int[] RandomFunction(int count, int minnum, int maxnum) { System.Random ra = new System.Random(unchecked((int)System.DateTime.Now.Ticks)); //生成多少个 int Count = count; int[] arrNum = new int[Count]; int tmp = 0; //最小值 int minValue = minnum; //最大值 int maxValue = maxnum; for (int i = 0; i < Count; i++) { tmp = ra.Next(minValue, maxValue+1); //随机取数 arrNum[i] = getNum(arrNum, tmp, minValue, maxValue, ra); //取出值赋到数组中 } return arrNum; } public int getNum(int[] arrNum, int tmp, int minValue, int maxValue, System.Random ra) { int n = 0; while (n <= arrNum.Length - 1) { if (arrNum == tmp) //利用循环判断是否有重复 { tmp = ra.Next(minValue, maxValue); //重新随机获取。 getNum(arrNum, tmp, minValue, maxValue, ra);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。 } n++; } return tmp; }
总结
为了 精确 推荐采用第一种方法,为了 快速无重复 推荐使用第三种方法
- C# Random循环生成随机数重复问题解决方案
- 关于C#中随机数的生成问题
- 有效解决C# Random生成随机数重复的问题
- C# 生成随机数重复问题
- C# 生成随机数问题
- 解决C# Random生成随机数重复的问题
- C#使用NMS与ActiveMQ通讯问题总结:如何生成Stomp.js中的headers对象
- Unity使用Random每次生成与上次不一致的随机数
- C#生成不重复随机数的方法
- C# 生成一个随机数
- C#实现在两个数字之间生成随机数的方法
- C#生成随机数的三种方法
- 用C#生成不重复的随机数
- unity C#调用windows的messagebox乱码问题
- C#生成随机数或随机字母
- 随机数的生成问题??
- C#的解题思路(1):不重复随机数的产生问题
- C# 随机数生成避免重复
- C# 生成随机数(转)
- 关于Servlet生成验证码的src为什么要带随机数的问题