web-dev-qa-db-fra.com

Plusieurs nombres aléatoires sont identiques

Duplicata possible:
Le générateur de nombres aléatoires ne génère qu'un seul nombre aléatoire

Une question pour débutant. J'ai un programme très simple qui dessine une ligne et je veux randomiser les emplacements, mais chaque fois que je crée une nouvelle instance de Random, il renvoie la même valeur. Où est le problème? Je vous remercie.

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();
}
29
Nejc Ucman

La raison en est que chaque fois que vous effectuez un nouveau Random, il est initialisé à l'aide de l'horloge. Ainsi, dans une boucle étroite (ou plusieurs appels les uns après les autres), vous obtenez la même valeur beaucoup de fois car toutes ces variables aléatoires sont initialisées avec la même graine.

Pour résoudre ce problème: Créez une seule variable aléatoire, de préférence en dehors de votre fonction et utilisez uniquement cette instance.

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));
}
56
Blachshma

Utilisez simplement la même instance:

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

Les nombres aléatoires dans la programmation ne sont pas vraiment aléatoires; ils sont basés sur un --- seed unique qui est pris et manipulé pour générer ce qui semble être un ensemble de nombres aléatoires. L'utilisation de la même graine se traduira par le même ensemble de nombres.

Le constructeur par défaut de la classe Random utilise le nombre de millisecondes écoulées depuis le démarrage du système comme graine, donc ce qui s'est réellement passé est la même graine a été utilisée.

Il n'y a vraiment aucune raison de créer plus d'une fois Random instance; l'instance unique générera un ensemble aléatoire de nombres à chaque exécution du code.

Pour prouver ma déclaration de graine par défaut ci-dessus, j'ai utilisé la réflexion:

// 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)
{
}

Et le 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;
}
10
Shadow Wizard

Vous ne devez pas créer un nouvel objet Random pour chaque numéro. Utilisez plutôt le même objet:

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]));
}
4
Adi Lester

Un générateur de nombres aléatoires (RNG) ne génère pas réellement de nombres aléatoires. Au lieu de cela, il utilise un algorithme pour définir une séquence de nombres, qui semblent être aléatoires. Cette séquence dépend du seed qui est exécuté à travers ledit algorithme au moment de la création de votre RNG.

Par défaut, les RNG sont créés en utilisant l'horloge du système comme graine, car l'horloge varie généralement à chaque exécution du programme, ce qui rend extrêmement difficile la prévision de la séquence "aléatoire".

Dans votre cas, il est très probable que l'horloge n'a pas changé entre la création d'un objet aléatoire et un autre; peut-être en raison de la réorganisation des instructions internes au processeur.

Comme l'indique Blachshma, il est préférable de ne créer qu'un seul objet aléatoire et de ne l'utiliser que.

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
}

Gardez à l'esprit que toute instance de System.Random ne sont pas garantis pour être thread-safe, ce qui signifie que si vous prévoyez d'avoir plusieurs threads partageant le même objet aléatoire, vous devez le verrouiller.

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

Si vous ne le faites pas, votre objet aléatoire pourrait être brisé, ce qui entraînerait des appels conséquents ne renvoyant que 0 en conséquence.

3
Nolonar

Vous n'avez besoin que d'une seule instance de la classe Random.

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();
    }
3
alu
    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();
    }
3
PaRiMaL RaJ