Random快速产生相同随机数的原因及解决方案

  1. 云栖社区>
  2. 博客>
  3. 正文

Random快速产生相同随机数的原因及解决方案

天才小龙 浏览911

老生常谈,还是那三句话:

学历代表你的过去,能力代表你的现在,学习代表你的将来

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

问题描述:很多时候我们可能需要在极短的时间内生成大量的随机数,但是你可能会发现生成了很多重复的随机数。并不是你所希望生成大量不同的数,或者说相同的数极少。

分析原因:Random是主要产生伪随机数的类,它主要包括两个构造函数(无参构造函数和带一个Int32类型参数的构造函数),无参构造函数主要采用系统时间作为随机种子,带参数的构造函数需要自己去指定随机种子。而在很短的时间内生成大量随机数的时候,由于时间相当短暂,很大的可能性一部分随机数生成时,取到作为随机种子的系统时间相同,因此产生出来的随机数就相同了。

解决方案:既然知道原因何在了,解决方案就可以出来了。要生成不同的随机数,我们只需要保证随机种子尽可能不重复(不能完全保证不重复)即可。Random类有两个构造函数,我们就可以考虑用两种方法去解决这个问题。(有更好、更多的解决办法的朋友,告诉我一声了,呵呵~~)

  1. 利用无参构造函数,既然它是采用系统时间作为随机种子,而取到的系统时间相同,才造成生成了重复的随机数,因此我们可以在生成一个随机数后延时一段时间,让它下次不取到相同的系统时间,这样随机种子也就不相同了。延时可以考虑使用Thread.Sleep(100),这里是延时0.1秒。
  2. 利用带参构造函数,我们想办法去生成尽可能不重复的随机种子。注意到MSDN中介绍Random.NextBytes()方法时,有这样一句话“要生成适合于创建随机密码的加密安全随机数,请使用如 RNGCryptoServiceProvider.GetBytes 这样的方法。”,它包含的意义是微软已经有现成的东西生成随机的密码,那我们就可以拿来用用了。我们就用它来生成我们的随机种子。

   可以写一个生成随机种子的方法,代码如下:

在此,贴下用法:

        public int GetRandSeed()
        {
            byte[] bytes = new byte[8];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }

然后再贴出一个具体应用。

生成固定前缀的身份证号(北京市市辖区身份证开头 110100):

#region 生成身份证号
        /// <summary>
        /// 身份证后四位
        /// </summary>
        /// <param name="codeLength"></param>
        /// <returns></returns>
        /// 
        private  string GetCode(int codeLength)
        {
            Random rand = new Random();
            string so = "1,2,3,4,5,6,7,8,9,0";
            string[] strArr = so.Split(',');
            string code = "";
            for (int i = 0; i < codeLength; i++)
            {
                code += strArr[rand.Next(0, strArr.Length)];
            }
            return code;
        }

        private string GetCodeForIdNo()
        {
            byte[] bytes = new byte[8];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            int j = Math.Abs(BitConverter.ToInt32(bytes, 0));
            if (j.ToString().Length == 1)
            {
                return GetCode(3) + j.ToString();
            }
            else if (j.ToString().Length == 2)
            {
                return GetCode(2) + j.ToString();
            }
            else if (j.ToString().Length == 3)
            {
                return GetCode(1) + j.ToString();
            }
            else if (j.ToString().Length == 4)
            {
                return j.ToString();
            }
            else
            {
                return j.ToString().Substring(0,4);
            }
        }

        public List<IdCard> CreateIdCard()
        {
            string CardFrist = "110100";//北京市市区
            List<IdCard> CMlist = new List<IdCard>();
            int Year = 1955;
            List<int> YearList = new List<int>();//年份范围
            List<int> monthList = new List<int>();//月份范围
            List<int> dayList = new List<int>();//天范围
            for (int i = -35; i < 36; i++)
            {
                YearList.Add(Year + i);
            }

            for (int i = 1; i < 13; i++)
            {
                monthList.Add(i);
            }
            //不考虑瑞年非闰年及月份的天数 最大28天
            for (int i =1; i < 29; i++)
            {
                dayList.Add(i);
            }
            //dd  
            XiCard(YearList); XiCard(monthList); XiCard(dayList);
            for (int i = 0; i < 100; i++)
            {
                IdCard CM = new IdCard();
                int Y_Len=YearList.Count;
                int M_Len=monthList.Count;
                int D_Len=dayList.Count;
                int Nyear = YearList[i % Y_Len];
                int Nmonth = monthList[i % M_Len];
                int Nday = dayList[i % D_Len];
                if (Nmonth < 10&&Nday<10)
                {
                    CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-0" + Nmonth.ToString() + "-0" + Nday.ToString());
                    CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo();
                    CMlist.Add(CM);
                }
                if (Nmonth < 10 && Nday > 10)
                {
                    CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-0" + Nmonth.ToString() + "-" + Nday.ToString());
                    CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo();
                    CMlist.Add(CM);
                }
                if (Nmonth > 10 && Nday > 10)
                {
                    CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-" + Nmonth.ToString() + "-" + Nday.ToString());
                    CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo();
                    CMlist.Add(CM);
                }
                if (Nmonth > 10 && Nday < 10)
                {
                    CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-" + Nmonth.ToString() + "-0" + Nday.ToString());
                    CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo();
                    CMlist.Add(CM);
                }

            }
            return CMlist;
        }

        /// <summary>
        /// dd
        /// </summary>
        /// <param name="list"></param>
        private void XiCard(List<int> list)
        {
            int i = list.Count;
            int j;
            if (i == 0)
            {
                return;
            }
            while (--i != 0)
            {
                Random ran = new Random();
                j = ran.Next() % (i + 1);
                int tmp = list[i];
                list[i] = list[j];
                list[j] = tmp;
            }
        }
        #endregion

Model 很简单,如下:

    public class IdCard
    {
        public string IdNo { get; set; }
        public DateTime BrithDay { get; set; }
    }

测试如下:

@陈卧龙的博客