5

作業中の別のプロジェクトをテストするために、一意の行のブロックを作成する必要があります。

そこで、長さ X のランダムな文字列を生成する簡単なプログラムを作成しました。

問題は、一度呼び出すとランダムな文字列を取得し、(for ループなどで) 再度呼び出すと、ループの実行全体で同じ文字列を取得することです。

キャッシュされているような気がしますが、.netがそれを行ったとは知らず、この時点で混乱しています。

呼び出しコード:

    StreamWriter SW = new StreamWriter("c:\\test.txt");
    int x = 100;
    while (x >0)
    {
        SW.WriteLine(RandomString(20));
        x--;
    }

ここに方法があります:

private static string RandomString(int Length)
{
    StringBuilder sb = new StringBuilder();
    Random randomNumber = new Random();

    for (int i = 0; i <= Length; ++i)
    {
        int x = randomNumber.Next(65, 122);
        sb.Append(Convert.ToChar(x));
    }
    return sb.ToString();        
}

出力は次のとおりです。

"VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
..................
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB"

それで、Random.next() は常に新しい乱数を返すと思ったのはなぜですか?

4

6 に答える 6

25

インスタンスを作成するRandom時間が近すぎます。各インスタンスはシステム クロックを使用して初期化され、クロックが変更されていないため、同じ乱数のシーケンスが何度も取得されます。

Randomクラスの単一のインスタンスを作成し、それを繰り返し使用します。

usingキーワードを使用して、使用StreamWriterが終了したときに を閉じて破棄します。forキーワードを使用すると、ループのコードを認識しやすくなります。

using (StreamWriter SW = new StreamWriter("c:\\test.txt")) {
   Random rnd = new Random();
   for (int x = 100; x > 0; x--) {
      SW.WriteLine(RandomString(rnd, 20));
   }
}

このメソッドは、Randomオブジェクトをパラメーターとして受け取ります。

また、ループ中に再割り当てする必要がないように、長さを使用して正しい容量で StringBuilder を初期化します。ループ内で <= の代わりに < 演算子を使用します。そうしないと、lengthパラメーターで指定された文字よりも 1 文字長い文字列が作成されます。

private static string RandomString(Random rnd, int length) {
   StringBuilder sb = new StringBuilder(length);
   for (int i = 0; i < length; i++) {
      int x = rnd.Next(65, 122);
      sb.Append((char)x);
   }
   return sb.ToString();        
}
于 2009-04-30T16:44:31.890 に答える
12

MSN のランダム コンストラクターの説明、この部分を参照してください。

デフォルトのシード値はシステム クロックから派生し、有限の分解能を持ちます。その結果、既定のコンストラクターの呼び出しによって連続して作成されるさまざまな Random オブジェクトは、同じ既定のシード値を持つため、同じ乱数のセットが生成されます。

したがって、Random() コンストラクターをプログラムの開始時に 1 回だけ呼び出すか、Random(int32) コンストラクターを使用して可変シードを自分で定義します。

于 2009-04-30T16:44:48.693 に答える
4

各呼び出しで新しい Random オブジェクトを作成するためです。

randomNumber をメソッドから移動して、クラス メンバーにするだけです。

private Random randomNumber = new Random();
private static string RandomString(int Length)
{
    StringBuilder sb = new StringBuilder();
    //...
}

すべてのソフトウェア ランダム ジェネレーターは 'pseudo random' であり、(開始) シードに基づいて一連の数値を生成します。同じシードを使用すると、同じシーケンスが生成されます。時々これは便利です。実行ごとに同じシーケンスを生成するようにプログラムを生成する場合は、 を使用できますnew Random(0)

編集: どうやら .Net Random クラスは自動シードされているようですが、私はそれを知りませんでした。他の人が指摘しているように、それはタイミングの問題です。

于 2009-04-30T16:43:00.820 に答える
3

同様の質問、多くの回答:

ランダムな文字列生成 - 次々に生成される 2 つの文字列は同じ結果になります

于 2009-04-30T16:45:35.163 に答える
3

randomNumber を 1 回だけ宣言する



public class MyClass
{
    private static Random randomNumber = new Random();

    private static string RandomString(int Length)
    {
        StringBuilder sb = new StringBuilder();  

        for (int i = 0; i ... Length; ++i)
        {
        int x = MyClass.randomNumber.Next(65, 122);
        sb.Append(Convert.ToChar(x));
        }
        return sb.ToString();        
    }
}
于 2009-04-30T16:49:44.780 に答える
1

乱数のシードは、所要時間が短いためすべて同じです。実際には、毎回同じシードで乱数ジェネレーターを再作成するため、Next() 呼び出しは同じランダム値を返します。

于 2009-04-30T16:46:05.070 に答える