.Net中咱們一般使用Random類生成隨機數,在一些場景下,我卻發現Random生成的隨機數並不可靠,在下面的例子中咱們經過循環隨機生成10個隨機數:算法
for (int i = 0; i < 10; i++) { Random random1 = new Random(); Console.WriteLine(random1.Next()); }
測試生成隨時基本都是相同的結果:dom
很顯然上面的結果是不靠譜的,爲何會這樣呢,由於微軟的Random類,發如今C#中生成隨機數使用的算法是線性同餘法,這種算法生成的不是絕對隨機,而是一種僞隨機數,線性同餘法算法的的公式是ide
:第n+1個數 = ( 第N個數 * a + b) % m ,公式中a、b和m分別爲常數,是生成隨機數的因子,若是以前從未經過同一個Random對象生成過隨機數(也就是調用過Next方法),那麼第N個隨機數爲將被指定爲一個默認的常數,這個常數在建立一個Random類時被默認值指定,Random也提供一個構造函數容許開發者使用本身的隨機數因子.函數
有人說要將 Random random1 = new Random(); 要放到循環的外面:性能
Random random2 = new Random(); for (int i = 0; i < 20; i++) { Console.WriteLine(random2.Next()); }
測試上面的代碼執行的結果是這樣的:測試
獲得結果仍是不靠譜的ui
有人說使用GUID產生填充因子:spa
for (int i = 0; i < 20; i++) { byte[] buffer = Guid.NewGuid().ToByteArray(); int iSeed = BitConverter.ToInt32(buffer, 0); Random random3 = new Random(iSeed); Console.WriteLine(random3.Next()); }
測試上面的代碼獲得的結果:線程
獲得的結果仍是不靠譜的。code
爲了生成更加可靠的隨機數,微軟在System.Security.Cryptography命名空間下提供一個名爲system.Security.Cryptography.RNGCryptoServiceProvider的類,它採用系統當前的硬件信息、進程信息、線程信息、系統啓動時間和當前精確時間做爲填充因子,經過更好的算法生成高質量的隨機數,它的使用方法以下所示:
for (int i = 0; i < 20; i++) { byte[] randomBytes = new byte[8]; System.Security.Cryptography.RNGCryptoServiceProvider rngServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider(); rngServiceProvider.GetBytes(randomBytes); int result = BitConverter.ToInt32(randomBytes, 0); result = System.Math.Abs(result); //求絕對值 Console.WriteLine(result); }
測試結果未發現重複的:
總結:
Random算法簡單,性能較高,適用於隨機性要求不高的狀況,因爲RNGCryptoServiceProvider在生成期間須要查詢上面提到的幾種系統因子,因此性能稍弱於Random類,但隨機數質量高,可靠性更好。使用哪種方式視狀況而定