web-dev-qa-db-fra.com

Pourquoi Rand () génère-t-il la même séquence de nombres à chaque exécution?

Chaque fois que je lance un programme avec Rand(), les mêmes résultats sont obtenus.

Exemple :

#include <iostream>
#include <cstdlib>

using namespace std;

int random (int low, int high) {
    if (low > high) return high;
    return low + (Rand() % (high - low + 1));
}
int main (int argc, char* argv []) {
    for (int i = 0; i < 5; i++) cout << random (2, 5) << endl;
}

Sortie:

3
5
4
2
3

Chaque fois que je lance le programme, il affiche les mêmes numéros à chaque fois. Y a-t-il un moyen de contourner ceci?

27
Patrick Lorio

La valeur de départ pour le générateur de nombres aléatoires n'est pas définie.

Si vous appelez srand(time(NULL)), vous obtiendrez plus de résultats aléatoires:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    srand(time(NULL));
    cout << Rand() << endl;
    return 0;
}

La raison en est qu'un nombre aléatoire généré à partir de la fonction Rand() n'est pas réellement aléatoire. C'est simplement une transformation. Wikipedia donne une meilleure explication de la signification du générateur de nombres pseudo-aléatoires: générateur de bits aléatoires déterministes. Chaque fois que vous appelez Rand(), il prend la valeur initiale et/ou le ou les derniers nombres aléatoires générés (le standard C ne spécifie pas l'algorithme utilisé, bien que C++ 11 dispose de fonctionnalités permettant de spécifier certains algorithmes populaires), exécute une opération mathématique sur ces chiffres, et retourne le résultat. Donc, si l’état initial est le même à chaque fois (comme si vous n’appeliez pas srand avec un nombre vraiment aléatoire), vous obtiendrez toujours les mêmes nombres «aléatoires».

Si vous voulez en savoir plus, vous pouvez lire ce qui suit:

http://www.dreamincode.net/forums/topic/24225-random-number-generation-102/

http://www.dreamincode.net/forums/topic/29294-making-pseudo-random-number-generators-more-random/

44
Robert Mason

Si vous appelez Rand() sans d'abord appeler srand(), il agira comme si vous aviez appelé implicitement srand(1). Le bit pertinent du C99 7.20.2.2 The srand function standard (sur lequel repose cstdlib) est le suivant:

Si Rand est appelé avant que des appels à srand aient été effectués, la même séquence sera générée que lorsque srand est appelé pour la première fois avec une valeur de départ égale à 1.

En d'autres termes, vous obtiendrez la même séquence à chaque fois. Vous pouvez changer votre main en:

int main (int argc, char* argv []) {
    srand (time (0));  // needs ctime header.
    for (int i = 0; i < 5; i++)
        cout << random (2, 5) << endl;
    wait ();
}

pour résoudre ce problème, en supposant que vous ne l'exécutez pas plus d'une fois par seconde.

Comme mentionné, vous aurez besoin de l'en-tête ctime pour cela. Vous devriez également entrer cstdlib puisque c’est là que Rand et srand résident. Il est également généralement préférable d’utiliser les en-têtes cXXX au lieu de ceux de XXX.h (par exemple, cmath plutôt que math.h).

Donc, ayant fait all ces modifications (et en utilisant des espaces de noms explicites, que je préfère bien que d'autres ne le fassent pas), je finirais avec:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>

void wait () {
    int e;
    std::cin >> e;
}

int random (int low, int high) {
    if (low > high) return high;
    return low + (std::Rand() % (high - low + 1));
}

int main (int argc, char* argv []) {
    std::srand (std::time (0));
    for (int i = 0; i < 5; i++)
        std::cout << random (2, 5) << '\n';
    wait ();
}

ce qui donne une séquence différente à chaque fois que je l'exécute, plusieurs fois quand même. Évidemment, il y a une limite stricte au moment où les données seront répétées (il n'y a que 45 possibilités) et le caractère "aléatoire" de la sortie signifie que cela peut se répéter aussi avant :-)

15
paxdiablo

C'est une caractéristique de la fonction Rand().

Ce que vous avez n’est pas un générateur de nombres aléatoires, mais plus strictement un "Générateur de nombres pseudo aléatoires" . Le fait de pouvoir reproduire les mêmes séquences aléatoires pour la même graine (vous utilisez la fonction srand(x)) peut être important pour reproduire des bogues ou pour préserver l’état au cours des exécutions du programme. 

Personnellement, j'utilise cette fonctionnalité pour pouvoir mettre en pause/persister les processus de rendu dans un rendu de terrain basé sur monte carlo . Un bel effet secondaire est que vous êtes en mesure de garantir différentes expériences de monte carlo sur différentes machines et donc de générer différents résultats garantis qui peuvent ensuite être réduits dans une étape finale vers un résultat final de qualité supérieure (bien sûr, vous pouvez les réutiliser ultérieurement). ce résultat final de qualité supérieure pour produire des résultats de qualité encore supérieure).

Notez cependant que ni C ni C++ ne définissent la séquence de nombres de Rand(). Donc, si vous avez besoin de séquences garanties sur toutes les plates-formes, utilisez l'un des nouveaux générateurs de nombres aléatoires de C++ 11 (par exemple, un mersenne twister ), lancez votre propre (certains générateurs sont presque triviaux sur un comportement de débordement spécifique, leur implémentation peut ne pas être triviale), ou utiliser un composant tiers (par exemple, boost :: random).

3
Sebastian Mach

Vous devez initialiser le générateur de nombres aléatoires (voir la fonction 'srand'). En supposant que vous n'effectuez pas de cryptographie, il est probablement suffisant de l'ajouter à la sortie de 'time'.

1
Michael Kohne

Vous obtenez réellement des nombres pseudo aléatoires. Pour les rendre "plus aléatoires", vous pouvez créer le générateur de nombres aléatoires en utilisant quelque chose qui "change" (le plus souvent l'heure actuelle).

0
John3136

utilisez randomize (). Il ensemence automatiquement la valeur ..__ Ou si vous voulez utiliser Rand (), vous pouvez l’ensemencer en utilisant srand (seedvalue); la valeur de départ peut être quelque chose comme le temps système .. ça vous donnera différents nombres aléatoires à chaque fois

0
Smatik