C#での乱数生成:Randomクラスと暗号学的なRandomNumberGeneratorの使い分け

目次

C#における乱数生成の必要性

プログラムにおいて「ランダムな値」が必要になる場面は数多くあります。ゲーム開発におけるアイテムのドロップ率、シミュレーションにおけるランダムなイベントの発生、あるいはテストデータの自動生成など、予測不可能な要素を取り入れるために乱数は不可欠です。

C#には、乱数を生成するための主要な方法が2つあります。

  1. System.Random クラス: 一般的かつ高速な「擬似乱数」を生成します。
  2. System.Security.Cryptography.RandomNumberGenerator クラス: 予測が非常に困難な「暗号学的に安全な乱数」を生成します。

この記事では、これら2つのクラスの基本的な使い方と、それぞれの適切な使い分けについて解説します。


System.Random クラス:一般的な擬似乱数

System.Randomクラスは、C#で乱数を扱う際の最も標準的な方法です。これは「擬似乱数ジェネレーター(PRNG)」であり、特定の「シード(種)」値に基づいて、統計的にランダムに見える数値のシーケンス(数列)を生成します。

インスタンスの生成と注意点

Randomクラスを使用するには、まずクラスのインスタンスを生成します。

// インスタンスを生成(シードは現在時刻などから自動設定される)
var randomGenerator = new Random();

非常に重要な注意点として、Randomのインスタンスを短時間のうちに(例えばforループの内部で)何度もnew Random()で生成しないでください。シード値が同じ時刻に基づいてしまうと、毎回同じ「ランダムな」数値が生成されてしまいます。

Randomのインスタンスは一度だけ生成し、それを使い回すのが基本です。

1. Next(minValue, maxValue):整数の乱数

指定した範囲の整数(int)を生成します。minValue(最小値)は含まれますが、**maxValue(最大値)は含まれない(未満である)**点に注意が必要です。

using System;

public class RandomNextExample
{
    public static void Main()
    {
        // インスタンスは一度だけ生成する
        var randomGenerator = new Random();

        Console.WriteLine("0以上10未満の整数を5個生成:");
        
        // 0, 1, 2, ... 9 のいずれかがランダムに選ばれる
        for (int i = 0; i < 5; i++)
        {
            int diceRoll = randomGenerator.Next(0, 10); 
            Console.Write($"{diceRoll}, ");
        }
        Console.WriteLine();
    }
}

出力結果(例):

0以上10未満の整数を5個生成:
7, 2, 9, 0, 4, 

2. NextDouble():0.0~1.0のdouble型乱数

NextDouble()メソッドは、0.0以上、1.0未満double型の値をランダムに返します。パーセンテージの計算(例: 確率0.25 = 25%)などに便利です。

using System;

public class RandomDoubleExample
{
    public static void Main()
    {
        var randomGenerator = new Random();

        Console.WriteLine("0.0以上1.0未満のdouble型を3個生成:");

        for (int i = 0; i < 3; i++)
        {
            double probability = randomGenerator.NextDouble();
            Console.WriteLine($"{probability:F5}"); // 小数点以下5桁で表示
        }
    }
}

出力結果(例):

0.0以上1.0未満のdouble型を3個生成:
0.81234
0.11792
0.45001

RandomNumberGenerator:暗号学的に安全な乱数

System.Randomが生成する擬似乱数は高速ですが、そのアルゴリズムとシード値がわかれば次に生成される数値を予測できてしまいます。

一方、System.Security.Cryptography.RandomNumberGeneratorは、セキュリティ用途向けに設計された「暗号論的擬似乱数ジェネレーター(CSPRNG)」です。ここで生成される乱数は、予測することが極めて困難です。

パスワードのランダム生成、セッションキーの作成、暗号化キーの生成など、セキュリティが重要な場面では必ずこちらを使用する必要があります。

GetInt32(minValue, maxValue):安全な整数の乱数

RandomNumberGeneratorクラスは、GetInt32という静的メソッドを提供しており、Randomクラスのようにインスタンスを生成する必要がなく、簡単に使用できます。

Nextメソッドと同様に、minValueは含まれますが、maxValueは含まれません

using System;
using System.Security.Cryptography; // この using が必要

public class SecureRandomExample
{
    public static void Main()
    {
        Console.WriteLine("安全な乱数を5個生成 (0~100):");

        // インスタンス生成は不要
        for (int i = 0; i < 5; i++)
        {
            // 0以上100未満の安全な乱数を取得
            int secureNumber = RandomNumberGenerator.GetInt32(0, 100);
            Console.Write($"{secureNumber}, ");
        }
        Console.WriteLine();
    }
}

出力結果(例):

安全な乱数を5個生成 (0~100):
78, 12, 99, 45, 62, 

どちらを使い分けるか

2つの方法の使い分けは、その「予測可能性」の要件によって決まります。

  • System.Random を使う場面:
    • 予測されても問題ない一般的な用途。
    • ゲーム(例: サイコロ、敵の動き)。
    • シミュレーション、テストデータの生成。
    • 速度が要求される場面。
  • RandomNumberGenerator を使う場面:
    • 予測されるとセキュリティ上の問題が発生する用途。
    • パスワードやPINコードの自動生成。
    • 暗号キー、セッションID、CSRFトークンの生成。
    • 公平性が厳密に求められる抽選。

まとめ

C#には2種類の乱数生成方法があり、それぞれに明確な役割があります。一般的なゲームやシミュレーションには高速なSystem.Randomを、セキュリティに関わる処理には予測不可能なRandomNumberGeneratorを使用する、という使い分けを正しく行うことが重要です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次