Random快速產生相同隨機數的原因及解決方案


老生常談,還是那三句話:

學歷代表你的過去,能力代表你的現在,學習代表你的將來

十年河東,十年河西,莫欺少年窮

學無止境,精益求精

問題描述:很多時候我們可能需要在極短的時間內生成大量的隨機數,但是你可能會發現生成了很多重復的隨機數。並不是你所希望生成大量不同的數,或者說相同的數極少。

分析原因: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; }
    }

測試如下:

@陳卧龍的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM