.NET TIPS

乱数を生成するには?

デジタルアドバンテージ
2003/06/06

 乱数(ランダムな数値)を生成するにはRandomクラス(System名前空間)を使用する。具体的には、まずRandomクラスのインスタンスを作成し、Nextメソッドを呼び出せばよい。例えば次のコードでは、0から99までの間のランダムな整数を1つ得ることができる。

Random rnd = new Random();
int randomNumber = rnd.Next(100);

 以降、Nextメソッドを呼び出すたびに別のランダムな整数が得られる。同様に、NextDoubleメソッドは、0.0から1.0の間のdouble型の乱数を生成する。また、NextBytesメソッドではバイト配列をパラメータで指定することにより、各要素に乱数が格納される。

Randomクラスを使用する場合の注意点

 コンピュータで乱数を生成する場合、ある数値をシード値(seed:種)として用い、その値を基にして特定の演算により乱数を生成していく。このため同じシード値を使用した場合、発生する乱数はまったく同じものとなる。

 Randomクラスで既定のコンストラクタ(パラメータのないコンストラクタ)を使用してインスタンスを作成した場合、そのシード値にはEnvironmentクラス(System名前空間)のTickCountプロパティが使用される。このプロパティは、PCを最後に起動してからの経過時間を返すのだが、その値はミリ秒単位である。このため、連続して複数のRandomクラスのインスタンスを作成した場合、シード値が同じインスタンスが作成されてしまう可能性がある。次のサンプル・プログラムはこの現象を実験するためのものだ。

// random1.cs

using System;

public class RandomNumber1 {
  static void Main() {

    for (int i = 0; i < 50; i++) {
      Random rnd = new Random();

      for (int j = 0; j < 10; j++) {
        Console.Write("{0} ", rnd.Next(10, 100));
      }
      Console.WriteLine(Environment.TickCount);
    }
    // 出力例:
    // 98 46 45 41 85 73 74 15 48 49 174438749
    // 98 46 45 41 85 73 74 15 48 49 174438749
    // 98 46 45 41 85 73 74 15 48 49 174438749
    // 98 46 45 41 85 73 74 15 48 49 174438749
    // 98 46 45 41 85 73 74 15 48 49 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 28 40 44 53 42 50 27 17 69 21 174438759
    // 48 34 43 65 88 26 70 18 91 83 174438769
    // 48 34 43 65 88 26 70 18 91 83 174438769
    // 48 34 43 65 88 26 70 18 91 83 174438769
    // 48 34 43 65 88 26 70 18 91 83 174438769
    // 48 34 43 65 88 26 70 18 91 83 174438769
    // ……

  }
}

// コンパイル方法:csc random1.cs
連続してRandomクラスのインスタンスを作成するC#のサンプル・プログラム(random1.cs)

 出力例を見ると、異なるインスタンスにもかかわらず、同じ乱数の系列が生成されてしまっているものがあることが分かる(そして、生成される乱数列の変化は、TickCountプロパティ値の変化と同期している)。このような乱数は、その目的からまったく不適切である。

 このような場合には、パラメータにシード値を指定できるコンストラクタのバージョンを使用し、プログラムで適当なシード値を与えてやればよい。そのように書き換えたものが次のサンプル・プログラムだ。

// random2.cs

using System;

public class test {
  static void Main() {

    int seed = Environment.TickCount;

    for (int i = 0; i < 50; i++) {
      Random rnd = new Random(seed++);

      for (int j = 0; j < 10; j++) {
        Console.Write("{0} ", rnd.Next(10, 100));
      }
      Console.WriteLine();
    }
    // 出力例:
    // 54 34 47 78 71 94 84 83 90 39
    // 11 61 20 98 22 83 34 38 11 72
    // 58 87 83 27 62 71 74 83 22 15
    // 15 24 56 46 13 60 25 38 33 48
    // 62 50 29 65 54 49 65 84 44 81
    // 19 76 92 84 94 37 15 39 55 25
    // 66 13 64 14 45 26 56 84 66 58
    // 23 39 37 33 86 15 96 39 78 91
    // 70 66 10 52 36 93 46 84 89 34
    // 27 92 73 71 77 82 86 39 10 67
    // 74 28 46 91 27 70 37 85 21 10
    // 31 55 19 20 68 59 77 40 32 44
    // 78 81 82 39 19 48 27 85 43 77
    // 35 18 55 58 59 36 68 40 54 20
    // 82 44 28 77 10 25 18 85 65 53
    // 39 70 91 97 51 14 58 40 77 86
    // 86 97 64 26 91 92 99 85 88 30
    // 43 33 36 45 42 81 49 41 99 63
    // 90 60 99 64 83 70 89 86 20 96
    // 47 86 72 83 33 58 40 41 31 39
    // ……

  }
}

// コンパイル方法:csc random2.cs
シート値を変えながらRandomクラスのインスタンスを作成するC#のサンプル・プログラム(random2.cs)

 このサンプル・プログラムではシード値を1ずつ増やしているだけだが、十分使えそうな乱数が得られている。

より厳密な乱数の生成

 詳細はここでは述べないが、暗号化に使用する乱数列が必要な場合には、より厳密な乱数を生成するためのRNGCryptoServiceProviderクラス(System.Security.Cryptography名前空間)も用意されている。このクラスは同名前空間の抽象クラスであるRandomNumberGeneratorクラスを実装したものだ。次のコードのように、このクラスのGetBytesメソッド(あるいはGetNonZeroBytesメソッド)を使用して、バイト配列に乱数列を得ることができる。

byte[] randoms = new byte[100];

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randoms);

 こちらのクラスではシード値の生成もより厳密になっているため、Randomクラスのような問題は発生しない。End of Article

カテゴリ:クラス・ライブラリ 処理対象:乱数
使用ライブラリ:Randomクラス(System名前空間)
使用ライブラリ:Environmentクラス(System名前空間)
使用ライブラリ:RNGCryptoServiceProviderクラス(System.Security.Cryptography名前空間)
 
この記事と関連性の高い別の.NET TIPS
重複のない乱数を生成(配列をシャッフル)するには?[C#/VB]
一時ファイル用のランダムなファイル名を生成するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間