34

重複の可能性:
1 つの乱数のみを生成する乱数ジェネレーター

初心者の質問です。線を描画する非常に単純なプログラムがあり、場所をランダム化したいのですが、Random の新しいインスタンスを作成するたびに同じ値が返されます。問題はどこだ?ありがとうございました。

private void Draw()
{
    Random random1 = new Random();
    int randomNumber1 = random1.Next(0, 300);
    Random random2 = new Random();
    int randomNumber2 = random2.Next(0, 300);
    Random random3 = new Random();
    int randomNumber3 = random3.Next(0, 300);
    Random random4 = new Random();
    int randomNumber4 = random4.Next(0, 300);
    System.Drawing.Graphics g = this.CreateGraphics();
    Pen green = new Pen(Color.Green, 5);
    g.DrawLine(green, new Point(randomNumber1, randomNumber2), 
                      new Point(randomNumber3, randomNumber4));
}

private void btndraw1_Click(object sender, EventArgs e)
{
    Draw();
}
4

7 に答える 7

63

これが発生する理由は、 new を実行するたびにRandom、時計を使用して初期化されるためです。したがって、タイトなループ (または次々に呼び出される多くの呼び出し) では、これらすべてのランダム変数が同じシードで初期化されるため、同じ値が何度も得られます。

これを解決するには: できれば関数の外側にランダム変数を 1 つだけ作成し、その 1 つのインスタンスのみを使用します。

Random random1 = new Random();
private void Draw()
{
    int randomNumber1 = random1.Next(0, 300);
    int randomNumber2 = random1.Next(0, 300);
    int randomNumber3 = random1.Next(0, 300);
    int randomNumber4 = random1.Next(0, 300);
    System.Drawing.Graphics g = this.CreateGraphics();
    Pen green = new Pen(Color.Green, 5);
    g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4));
}
于 2013-02-03T15:10:25.930 に答える
10

同じインスタンスを使用するだけです。

Random random = new Random();
int randomNumber1 = random.Next(0, 300);
int randomNumber2 = random.Next(0, 300);
//...

プログラミングにおける乱数は実際にはランダムではありません。それらは、乱数のセットのように見えるものを生成するために取得および操作されるいくつかの一意のシードに基づいています。同じシードを使用すると、同じ数のセットになります。

クラスのデフォルトのコンストラクターはRandom、システムが開始してから経過したミリ秒数をシードとして使用しているため、実際に起こったことは同じシードが使用されたことです。

Random複数のインスタンスを作成する理由はまったくありません。単一のインスタンスは、コードの実行ごとに乱数のセットを生成します。

上記のデフォルト シードのステートメントを証明するために、リフレクションを使用しました。

// System.Random
/// <summary>Initializes a new instance of the <see cref="T:System.Random" /> class, using a time-dependent default seed value.</summary>
public Random() : this(Environment.TickCount)
{
}

そしてEnvironment.TickCount

// System.Environment
/// <summary>Gets the number of milliseconds elapsed since the system started.</summary>
/// <returns>A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.</returns>
/// <filterpriority>1</filterpriority>
public static extern int TickCount
{
    [SecuritySafeCritical]
    [MethodImpl(MethodImplOptions.InternalCall)]
    get;
}
于 2013-02-03T15:09:40.643 に答える
4

乱数ジェネレーター (RNG) は、実際には乱数を生成しません。代わりに、ランダムに見える一連の数字を定義するアルゴリズムを使用します。このシーケンスは、seedRNG の作成時に実行されるアルゴリズムによって異なります。

デフォルトでは、システムのクロックをシードとして使用して RNG が作成されます。クロックは通常、プログラムが実行されるたびに変化し、「ランダムな」シーケンスを予測することが非常に困難になるためです。

あなたの場合、ランダムオブジェクトの作成と別のオブジェクトの作成の間でクロックが変わらなかった可能性が非常に高いです。おそらく、命令の CPU 内部の再順序付けが原因です。

Blachshma が述べているように、ランダム オブジェクトを 1 つだけ作成し、それのみを使用するのが最善です。

public static Random MyRNG = new Random(); // create a single static random object, that you can use across all classes
private void Draw()
{
    randomNumber1 = MyRNG.Next(0, 300);
    randomNumber2 = MyRNG.Next(0, 300);
    // and so forth
}

のインスタンスSystem.Randomがスレッドセーフであるとは限らないことに注意してください。つまり、複数のスレッドで同じランダム オブジェクトを共有する場合は、ロックする必要があります。

lock (MyRNG)
{
    randomNumber = MyRNG.Next(0, 300);
}

そうしないと、ランダム オブジェクトが破損し、結果として 0 のみが返される結果の呼び出しにつながる可能性があります。

于 2013-02-03T16:02:13.627 に答える
4

Random数値ごとに新しいオブジェクトを作成しないでください。代わりに、同じオブジェクトを使用します。

Random r = new Random();

private void Draw()
{
    // Create 4 random numbers
    int[] numbers = Enumerable.Range(0, 4).Select(x => r.Next(0, 300)).ToArray();

    System.Drawing.Graphics g = this.CreateGraphics();
    Pen green = new Pen(Color.Green, 5);
    g.DrawLine(green, new Point(numbers[0], numbers[1]),
                      new Point(numbers[2], numbers[3]));
}
于 2013-02-03T15:16:26.303 に答える
3

Random クラスのインスタンスは 1 つだけ必要です。

private void Draw()
    {
        Random random1 = new Random();
        int randomNumber1 = random1.Next(0, 300);

        int randomNumber2 = random1.Next(0, 300);

        int randomNumber3 = random1.Next(0, 300);

        int randomNumber4 = random1.Next(0, 300);

        System.Drawing.Graphics g = this.CreateGraphics();
        Pen green = new Pen(Color.Green, 5);
        g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4));
    }


    private void btndraw1_Click(object sender, EventArgs e)
    {
        Draw();
    }
于 2013-02-03T15:10:56.170 に答える
3
    private static readonly Random Random1 = new Random();

    private void Draw()
    {

        int randomNumber1 = Random1.Next(0, 300);
        int randomNumber2 = Random1.Next(0, 300);
        int randomNumber3 = Random1.Next(0, 300);
        int randomNumber4 = Random1.Next(0, 300);
        System.Drawing.Graphics g = this.CreateGraphics();
        Pen green = new Pen(Color.Green, 5);
        g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4));
    }


    private void btndraw1_Click(object sender, EventArgs e)
    {
        Draw();
    }
于 2013-02-03T15:11:36.910 に答える
-4

.Net のランダムなクラスが必要とするのは、日付値をシードとして使用できるシード値であり、それは機能します。

private void Draw()
    {
        Random random1 = new Random(unchecked((int)DateTime.Now.Ticks << (int)100));
        int randomNumber1 = random1.Next(0, 300);
        Random random2 = new Random(unchecked((int)DateTime.Now.Ticks << (int)200));
        int randomNumber2 = random2.Next(0, 300);
        Random random3 = new Random(unchecked((int)DateTime.Now.Ticks << (int)300));
        int randomNumber3 = random3.Next(0, 300);
        Random random4 = new Random(unchecked((int)DateTime.Now.Ticks << (int)400));
        int randomNumber4 = random4.Next(0, 300);
        System.Drawing.Graphics g = this.CreateGraphics();
        Pen green = new Pen(Color.Green, 5);
        g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4));
    }


private void btndraw1_Click(object sender, EventArgs e)
{
    Draw();
}
于 2013-02-03T15:19:22.740 に答える