C# でランダム クラスをシードする

Syed Hassan Sabeeh Kazmi 2024年2月15日
  1. C# で乱数クラスをシードする関数を作成する
  2. Random() クラスを使用して C# でランダム クラスをシードする
  3. Environment.TickCount プロパティを使用して C# でランダム クラスをシードする
  4. C#RNGCryptoServiceProvider クラスを使用してランダム クラスをシードする
C# でランダム クラスをシードする

このチュートリアルでは、アプリケーションでランダム性を実現するために C# でクラスをシードする方法について説明します。 クラスをシードする主な方法は 4つあります。すべては Random クラスから始まり、インスタンスを初期化し、Next() メソッドを呼び出してランダムな整数を取得することで、特定の範囲のない数値を生成できます。 NextDouble() メソッドを使用した 10 進数。

クラスをゼロから作成できます。 Random クラス、Environment.TickCount、または RNGCryptoServerProvider クラスを使用して、C# でランダム クラスをシードできます。

C# で乱数クラスをシードする関数を作成する

public static int random_func(int _min, int _max){} のような関数を作成し、Random クラスからオブジェクトを作成して、min 値と max 値に対して Next() メソッドを実行します。

Random クラスのプライベートな静的オブジェクトに対して操作を実行するパブリック関数を保持する静的クラスを作成することで、この手法を繰り返すことができます。 真のステートレス静的メソッドの場合、Guid に厳密に依存して、Guid.NewGuid().GetHashCode() などで乱数を生成できます。

using System;
using System.Windows.Forms;

namespace seed_random_class {
  public partial class Form1 : Form {
    // function to get a random number
    public static int RandomNumber(int min, int max) {
      Random random = new Random();
      return random.Next(min, max);
    }
    public Form1() {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e) {}

    private void label1_Click(object sender, EventArgs e) {}

    private void button1_Click(object sender, EventArgs e) {
      int min = 0;
      int max = 10;
      int return_num;
      return_num = Form1.RandomNumber(min, max);
      label1.Text = return_num.ToString();

      /* alternative approach

      byte[] _random = new byte[6];
      for (int i = 0; i < 6; ++i)
      _random[i] = (byte)(Form1.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);

      */
    }
  }
}

出力:

ランダム クラスをシードする関数を作成する

Guid の目的は一様分布ではなく一意であることであり、ほとんどの場合、ランダム性の反対であり、一様分布を実装していないことを理解することが重要です。そのため、Random クラスに基づいて関数を作成することが有効なアプローチです。 . また、Random((int)DateTime.Now.Ticks) のように、より大きな予測不可能な数値をランダム クラスにシードすることで、ランダム性を向上させることもできます。

Random() クラスを使用して C# でランダム クラスをシードする

Random クラスのインスタンスを作成し、ループ内でそのインスタンスに Next() メソッドを適用することは、C# でクラスをシードするための常に最良の方法です。 単一の Random クラス インスタンスが生成する数値は、常に均一に分散されます。すべての乱数に対して新しい Random クラス インスタンスをすばやく連続して作成することにより、同一の乱数を生成するために同じ値をシードすることができます。

完全を期すために Random クラスを再シードし、新しいシードから新しいインスタンスを作成することをお勧めします。再シードは、予測可能性が問題になる場合に最適なオプションです。 パターン認識が攻撃者側から適用されるよりも速く再シードする必要があり、2つのジェネレーターに同じ値がシードされないようにすることができます。

new Random() は常にシステム クロックを使用して初期化されるため、同じ値を取得できます。 したがって、単一の Random インスタンスを保持し、同じインスタンスで Next() メソッドを使用し続ける必要があります。

using System;
using System.Windows.Forms;

namespace seed_random_class {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e) {}

    private void label1_Click(object sender, EventArgs e) {}

    private void button1_Click(object sender, EventArgs e) {
      var _random = new Random();
      for (int i = 0; i < 100; ++i) label1.Text = _random.Next(1, 100).ToString();
    }
  }
}

出力:

Random() クラスを使用してランダム クラスをシードする

最も重要なことは、シードを Next() と同期させるために lock が必要なことです。これは、Next() を複数のスレッドに同時に適用すると、結果をさらにランダムにすることができるためです。 内部実装が壊れる可能性があります。 lock はスレッドの安全性を保証し、同期は最大のランダム性を達成するための最良の方法です。

Random クラス インスタンスで lock を使用することも代替手段ですが、他の方法よりもスレッド セーフではありません。 Random オブジェクトのスレッドとパラメーターなしのコンストラクターを使用しているとします。

その場合、Thread.Sleep メソッドの呼び出しによって引き起こされる遅延に直面する可能性があり、そのオブジェクトに対して異なるシード値が生成され、異なるシーケンスの乱数が生成される可能性があります。

Environment.TickCount プロパティを使用して C# でランダム クラスをシードする

System 名前空間に属し、システムが起動してからのミリ秒数を取得することが重要であり、32 ビットの符号付き整数を表します。 このプロパティは、Int32.MinValueInt32.MaxValue の間を循環し、それぞれ負の数と正の数を表します。符号ビットを削除して、24.9 日ごとに 0 と最大の正の値の間を循環する非負の数を生成できます。 .

その 32 ビット符号付き整数の解像度は、システム タイマーの範囲の 10 ~ 16 ミリ秒の解像度に制限されます。 最も重要なのは、System.Random で使用される実装が Environment.TickCount であり、DateTime.UtcNow.Ticks をキャストする必要がなく、C# アプリケーション全体で乱数クラスのシードの再利用が容易になることです。

using System;
using System.Threading;  // essential namespace for threading
using System.Windows.Forms;

namespace seed_random_class {
  public static class StaticRandom {
    // initialize the seed
    private static int _var_seed;

    // a thread-safe approach to access the random class via seed
    // `<Random>` implies the Random class
    private static ThreadLocal<Random> local_thread =
        new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref _var_seed)));

    // method that utilizes the `Environment.TickCount` property
    static StaticRandom() {
      _var_seed = Environment.TickCount;
    }

    public static Random class_inst {
      get { return local_thread.Value; }
    }
  }
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e) {}

    private void label1_Click(object sender, EventArgs e) {}

    private void button1_Click(object sender, EventArgs e) {
      label1.Text = StaticRandom.class_inst.Next(1, 100).ToString();
    }
  }
}

出力:

Environment.TickCount プロパティを使用してランダム クラスをシードする

C#RNGCryptoServiceProvider クラスを使用してランダム クラスをシードする

いくつかの特殊なケースでは、RNGCryptoServerProver クラスの使用が必要になります。 System.Security.Cryptography 名前空間に属し、CSP (Cryptographic Service Provider) によって提供される実装を使用して暗号化 RNG (乱数ジェネレーター) を実装し、継承することはできません。

IDisposable インターフェイスを実装し、try/catch ブロックで Dispose メソッドを呼び出すことができるため、直接的または間接的に破棄することが重要です。 C# では、using コンストラクトを使用して破棄し、ランダム クラスの完全なシードを作成できます。

System.Security.Cryptography.RNGCryptoServiceProvider クラスはスレッド セーフであり、既知のシードから値を再現することで真のニーズに応えます。 ただし、2つの独立した値を生成できる関数を作成することは数学的に不可能であり、これは暗号化スキームが完全に安全ではないことも意味し、使用するためのコストが高すぎる場合もあります。

using System;
using System.Windows.Forms;

namespace seed_random_class {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e) {}

    private void label1_Click(object sender, EventArgs e) {}

    private void button1_Click(object sender, EventArgs e) {
      byte[] foo = { 0x32, 0x00, 0x1E, 0x00 };
      System.Security.Cryptography.RNGCryptoServiceProvider prov =
          new System.Security.Cryptography.RNGCryptoServiceProvider();
      prov.GetBytes(foo);
    }
  }
}

出力:

RNGCryptoServiceProvider クラスを使用してランダム クラスをシードする

Next(int) または Next(int min, int max) メソッドを使用して範囲内の乱数を生成するか、Next() および NextBytes() を使用してそれぞれランダムな整数と系列を生成できます バイト値の。 コンストラクターのオーバーロードを介してシードを提供するか、フレームワークがこれを処理します。

Random クラスをインスタンス化するのはコストのかかる方法であり、やりすぎると C# アプリケーションのパフォーマンスが低下する可能性があります。 代わりに、単一の Random インスタンスをインスタンス化し、Next() メソッドを複数回呼び出します。 暗号化は、C# でランダム クラスをシードするためのより安全で保護的なアプローチです。

Syed Hassan Sabeeh Kazmi avatar Syed Hassan Sabeeh Kazmi avatar

Hassan is a Software Engineer with a well-developed set of programming skills. He uses his knowledge and writing capabilities to produce interesting-to-read technical articles.

GitHub

関連記事 - Csharp Math