乱数を作ります。(System.Random, RNGCryptoServiceProvider)

コンピュータでランダムな値を作る場合は、サイコロを振るのとは違い計算によって求めます。そのため計算によって作ることから疑似乱数と呼ばれます。疑似という言葉が付くと乱数として不完全な物のように思えますが、コンピュータで作る乱数は、どの程度ランダムであるかどうかに関わらず、すべて疑似乱数と呼ばれるので誤解しないようにする必要があります。逆にサイコロを振ることは真の乱数と呼ばれます。

ランダムな値を作るときに、どの程度厳密にランダムさが要求されるかによって使用するクラスを使い分けます。

・System.Random
 簡易な方法。シード(乱数の種)を与えて乱数を作成するため、シードが同じだと同じ乱数ができてしまう。シードに日時などを使うなどして同じ乱数になる事を防ぎます。計算量が少なく簡単に乱数を作成できるので、厳密さが要求されない場合、こちらを使います。

・RNGCryptoServiceProvider
 厳密な方法。完全にランダムな値が作成できます。暗号に使う場合はこちらを採用します。計算量が多く時間が掛かる。
 
実際のところ、どのくらい差が出るのか乱数を100万個ほど作って測ってみることにします。


System.Random で 1個の乱数作成処理を100万回実行する。 5381ms
System.Random で 100万個の乱数作成処理を1回実行する。 15ms
RNGCryptoServiceProvider で 1個の乱数作成処理を100万回実行する。 4763ms
RNGCryptoServiceProvider で 100万個の乱数作成処理を1回実行する。 19ms

面白い結果が出ました。殆ど差がありません、両方ともかなり高速です。いつでも気軽にRNGCryptoServiceProviderを使っても良いようです。

検証用コード


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;

namespace RandomGenerator
{
class Program
{

const int REPEAT_COUNT = 1000000;

static void Main(string[] args)
{

Stopwatch sw = new Stopwatch();

sw.Reset();
sw.Start();

SystemRandomRepeat();

sw.Stop();

Console.WriteLine(String.Format("System.Random で 1個の乱数作成処理を100万回実行する。 {0}ms", sw.ElapsedMilliseconds.ToString()));

sw.Reset();
sw.Start();

SystemRandomOnece();

sw.Stop();

Console.WriteLine(String.Format("System.Random で 100万個の乱数作成処理を1回実行する。 {0}ms", sw.ElapsedMilliseconds.ToString()));

sw.Reset();
sw.Start();

RNGCryptoServiceProviderRepeat();

sw.Stop();

Console.WriteLine(String.Format("RNGCryptoServiceProvider で 1個の乱数作成処理を100万回実行する。 {0}ms", sw.ElapsedMilliseconds.ToString()));

sw.Reset();
sw.Start();

RNGCryptoServiceProviderOnece();

sw.Stop();

Console.WriteLine(String.Format("RNGCryptoServiceProvider で 100万個の乱数作成処理を1回実行する。 {0}ms", sw.ElapsedMilliseconds.ToString()));

Console.ReadLine();


}

static void SystemRandomOnece()
{

Byte[] rndBuffer = new Byte[REPEAT_COUNT];
Random rnd = new Random(System.DateTime.Now.Millisecond);
rnd.NextBytes(rndBuffer);

}

static void SystemRandomRepeat()
{

for(int i= 0; i