J'essaye de faire un jeu avec des dés, et j'ai besoin d'avoir des nombres aléatoires dedans (pour simuler les côtés du dé. Je sais comment le faire entre 1 et 6). En utilisant
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned)time(0));
int i;
i = (rand()%6)+1;
cout << i << "\n";
}
ne fonctionne pas très bien, car lorsque j'exécute le programme plusieurs fois, voici le résultat que j'obtiens:
6
1
1
1
1
1
2
2
2
2
5
2
Je veux donc une commande qui générera un nombre aléatoire différent à chaque fois, pas le même 5 fois de suite. Y a-t-il une commande qui fera cela?
Réponses:
Le problème le plus fondamental de votre application de test est que vous appelez
srand
une fois, puisrand
une fois et que vous quittez.Le but de la
srand
fonction est d'initialiser la séquence de nombres pseudo-aléatoires avec une graine aléatoire.Cela signifie que si vous passez la même valeur à
srand
dans deux applications différentes (avec le mêmesrand
/rand
implémentation), vous obtiendrez exactement la même séquence derand()
valeurs lues par la suite dans les deux applications.Cependant, dans votre exemple d'application, la séquence pseudo-aléatoire se compose d'un seul élément - le premier élément d'une séquence pseudo-aléatoire générée à partir de la valeur de départ égale à l'heure de
second
précision actuelle. Qu'attendez-vous alors de la sortie?Évidemment, lorsque vous exécutez l'application sur la même seconde - vous utilisez la même valeur de départ - votre résultat est donc bien sûr le même (comme Martin York l'a déjà mentionné dans un commentaire à la question).
En fait, vous devriez appeler
srand(seed)
une fois, puis appelerrand()
plusieurs fois et analyser cette séquence - elle devrait paraître aléatoire.ÉDITER:
Oh je comprends. Apparemment, la description verbale ne suffit pas (peut-être la barrière de la langue ou quelque chose du genre ... :)).
D'ACCORD. Exemple de code C à l'ancienne basé sur les mêmes
srand()/rand()/time()
fonctions que celles utilisées dans la question:^^^ CETTE séquence d'une seule exécution du programme est censée paraître aléatoire.
EDIT2:
Lorsque vous utilisez une bibliothèque standard C ou C ++, il est important de comprendre qu'à partir de maintenant, il n'y a pas une seule fonction ou classe standard produisant des données réellement aléatoires de manière définitive (garantie par le standard). Le seul outil standard qui aborde ce problème est std :: random_device qui malheureusement ne fournit toujours pas de garanties d'aléa réel.
En fonction de la nature de l'application, vous devez d'abord décider si vous avez vraiment besoin de données vraiment aléatoires (imprévisibles). Le cas notable où vous avez certainement besoin d'un vrai hasard est la sécurité de l'information - par exemple, la génération de clés symétriques, de clés privées asymétriques, de valeurs de sel, de jetons de sécurité, etc.
Cependant, les nombres aléatoires de niveau de sécurité constituent une industrie distincte qui mérite un article distinct.
Dans la plupart des cas, le générateur de nombres pseudo-aléatoires est suffisant - par exemple pour les simulations scientifiques ou les jeux. Dans certains cas, une séquence pseudo-aléatoire définie de manière cohérente est même requise - par exemple, dans les jeux, vous pouvez choisir de générer exactement les mêmes cartes au moment de l'exécution pour éviter de stocker beaucoup de données.
La question originale et la multitude récurrente de questions identiques / similaires (et même de nombreuses «réponses» erronées à celles-ci) indiquent qu'il est avant tout important de distinguer les nombres aléatoires des nombres pseudo-aléatoires ET de comprendre ce qu'est une séquence de nombres pseudo-aléatoires dans le premier endroit ET pour réaliser que les générateurs de nombres pseudo-aléatoires ne sont PAS utilisés de la même manière que vous pourriez utiliser de vrais générateurs de nombres aléatoires.
^^^ CE type d'attentes intuitives EST TRÈS FAUX et nuisibles dans tous les cas impliquant des générateurs de nombres pseudo-aléatoires - bien qu'ils soient raisonnables pour de vrais nombres aléatoires.
Bien que la notion significative de "nombre aléatoire" existe, il n'y a pas de "nombre pseudo-aléatoire". Un générateur de nombres pseudo-aléatoires produit en fait une séquence de nombres pseudo-aléatoires .
Lorsque les experts parlent de la qualité du PRNG, ils parlent en fait des propriétés statistiques de la séquence générée (et de ses sous-séquences notables). Par exemple, si vous combinez deux PRNG de haute qualité en les utilisant tous les deux à tour de rôle - vous pouvez produire une mauvaise séquence résultante - bien qu'ils génèrent de bonnes séquences chacune séparément (ces deux bonnes séquences peuvent simplement se corréler l'une à l'autre et donc se combiner mal).
La séquence pseudo-aléatoire est en fait toujours déterministe (prédéterminée par son algorithme et ses paramètres initiaux) c'est-à-dire qu'elle n'a en fait rien d'aléatoire.
Spécifiquement
rand()
/srand(s)
paire de fonctions fournit une séquence de nombres pseudo-aléatoires singulière par processus non thread-safe (!) Générée avec un algorithme défini par l'implémentation. La fonctionrand()
produit des valeurs dans la plage[0, RAND_MAX]
.Citation de la norme C11:
Beaucoup de gens s'attendent raisonnablement à ce que
rand()
cela produise une séquence de nombres semi-indépendants uniformément distribués dans l'intervalle0
deRAND_MAX
. Eh bien, il devrait très certainement (sinon c'est inutile) mais malheureusement non seulement la norme ne l'exige pas - il existe même une clause de non-responsabilité explicite qui déclare "il n'y a aucune garantie quant à la qualité de la séquence aléatoire produite" . Dans certains cas historiquesrand
/ lasrand
mise en œuvre était en effet de très mauvaise qualité. Même si dans les implémentations modernes, il est très probablement assez bon - mais la confiance est brisée et pas facile à récupérer. Outre sa nature non thread-safe, son utilisation en toute sécurité dans les applications multi-threads est délicate et limitée (toujours possible - vous pouvez simplement les utiliser à partir d'un thread dédié).Le nouveau modèle de classe std :: mersenne_twister_engine <> (et ses typedefs pratiques -
std::mt19937
/std::mt19937_64
avec une bonne combinaison de paramètres de modèle) fournit un générateur de nombres pseudo-aléatoires par objet défini dans la norme C ++ 11. Avec les mêmes paramètres de modèle et les mêmes paramètres d'initialisation, différents objets généreront exactement la même séquence de sortie par objet sur n'importe quel ordinateur dans n'importe quelle application construite avec une bibliothèque standard compatible C ++ 11. L'avantage de cette classe est sa séquence de sortie de haute qualité prévisible et sa cohérence totale entre les implémentations.Il y a aussi plus de moteurs PRNG définis dans le standard C ++ 11 - std :: linear_congruential_engine <> (historiquement utilisé comme
srand/rand
algorithme de qualité équitable dans certaines implémentations de bibliothèques standard C) et std :: subtract_with_carry_engine <> . Ils génèrent également des séquences de sortie par objet entièrement définies dépendant des paramètres.Exemple de remplacement moderne C ++ 11 du code C obsolète ci-dessus:
La version du code précédent qui utilise std :: uniform_int_distribution <>
la source
rand()
etsrand()
. Pouvez-vous le mettre à jour?rand()
etsrand()
. En fait, il répond simplement à la question avec une description fournie. Il est évident d'après la description (qui utiliserand
/srand
) que les concepts de base de la génération de nombres pseudo-aléatoires doivent être expliqués - comme la signification même de la séquence pseudo-aléatoire et de sa graine. Je suis en train de faire exactement cela et utiliser le plus simple et familierrand
/srand
combinaison. Ce qui est drôle, c'est que certaines autres réponses - même avec une très grande cote - souffrent des mêmes malentendus que l'auteur de la question.std::rand/std::srand
fonctionnalités de la bibliothèque C ++ commestd::random_device<>
, std :: mersenne_twister_engine <> et la multitude de distributions aléatoires nécessitent quelques explications.L'utilisation de modulo peut introduire un biais dans les nombres aléatoires, en fonction du générateur de nombres aléatoires. Voir cette question pour plus d'informations. Bien sûr, il est parfaitement possible d'obtenir des nombres répétés dans une séquence aléatoire.
Essayez quelques fonctionnalités C ++ 11 pour une meilleure distribution:
Voir cette question / réponse pour plus d'informations sur les nombres aléatoires C ++ 11. Ce qui précède n'est pas le seul moyen de le faire, mais c'est un moyen.
la source
%6
est extrêmement faible. Peut-être significatif si vous écrivez un jeu de craps à utiliser à Las Vegas, mais sans conséquence dans presque tous les autres contextes.random_device
etmt19937
déjà, il n'y a littéralement aucune raison de ne pas tout faire et d'utiliser la normeuniform_int_distribution
aussi.Si vous utilisez des bibliothèques boost, vous pouvez obtenir un générateur aléatoire de cette manière:
Où la fonction
current_time_nanoseconds()
donne l'heure actuelle en nanosecondes qui est utilisée comme graine.Voici une classe plus générale pour obtenir des entiers et des dates aléatoires dans une plage:
la source
http://en.cppreference.com/w/cpp/numeric/random/rand
la source
%6
.) Et si vous avez décidé d'utiliser l'std::rand
API C ++ de larand
fonction de bibliothèque C alors pourquoi ne pas utiliserstd::time
etstd::srand
pour des raisons de cohérence de style C ++?Peut obtenir le
Randomer
code de classe complet pour générer des nombres aléatoires à partir d'ici!Si vous avez besoin de nombres aléatoires dans différentes parties du projet, vous pouvez créer une classe distincte
Randomer
pour incorporer toutrandom
ce qui s'y trouve.Quelque chose comme ca:
Une telle classe serait utile plus tard:
Vous pouvez consulter ce lien comme exemple sur la manière dont j'utilise une telle
Randomer
classe pour générer des chaînes aléatoires. Vous pouvez également utiliserRandomer
si vous le souhaitez.la source
Chaque fois que vous effectuez une recherche Web de base
random number generation
dans le langage de programmation C ++, cette question est généralement la première à apparaître! Je veux jeter mon chapeau dans le ring pour, espérons-le, mieux clarifier le concept de génération de nombres pseudo-aléatoires en C ++ pour les futurs codeurs qui chercheront inévitablement cette même question sur le web!Les bases
La génération de nombres pseudo-aléatoires implique l'utilisation d'un algorithme déterministe qui produit une séquence de nombres dont les propriétés ressemblent approximativement à des nombres aléatoires . Je dis à peu près ressembler , car le vrai hasard est un mystère assez insaisissable en mathématiques et en informatique. Par conséquent, pourquoi le terme pseudo-aléatoire est utilisé pour être plus pédantiquement correct!
Avant de pouvoir utiliser réellement un PRNG, c'est-à-dire,
pseudo-random number generator
vous devez fournir à l'algorithme une valeur initiale souvent appelée aussi la graine . Cependant, la graine ne doit être définie qu'une seule fois avant d' utiliser l'algorithme lui-même!Ainsi, si vous voulez une bonne séquence de nombres, vous devez fournir une amorce suffisante au PRNG!
L'ancienne voie C
La bibliothèque standard rétrocompatible de C que C ++ a, utilise ce qu'on appelle un générateur congruentiel linéaire trouvé dans le
cstdlib
fichier d' en- tête! Ce PRNG fonctionne grâce à une fonction discontinue par morceaux qui utilise l'arithmétique modulaire, c'est-à-dire un algorithme rapide qui aime utiliser lemodulo operator '%'
. Ce qui suit est l'utilisation courante de ce PRNG, en ce qui concerne la question initiale posée par @Predictability:L'usage courant du PRNG de C contient toute une série de problèmes tels que:
std::rand()
n'est pas très intuitive pour la génération appropriée de nombres pseudo-aléatoires entre une plage donnée, par exemple, la production de nombres entre [1, 6] comme le souhaitait @Predictability.std::rand()
élimine la possibilité d'une distribution uniforme de nombres pseudo-aléatoires, en raison du principe de Pigeonhole .std::rand()
s'ensemencée par le planstd::srand( ( unsigned int )std::time( nullptr ) )
technique n'est pas correct, cartime_t
est considéré comme un type restreint . Par conséquent, la conversion detime_t
enunsigned int
n'est pas garantie!Pour des informations plus détaillées sur les problèmes généraux liés à l'utilisation du PRNG de C et sur la manière de les contourner, veuillez consulter Utilisation de rand () (C / C ++): Conseils pour la fonction rand () de la bibliothèque standard C !
La méthode C ++ standard
Depuis la publication de la norme ISO / CEI 14882: 2011, c'est-à-dire C ++ 11, la
random
bibliothèque est en dehors du langage de programmation C ++ depuis un certain temps. Cette bibliothèque est équipée de plusieurs PRNGs, et différents types de distribution tels que: distribution uniforme , la distribution normale , distribution binomiale , etc. L'exemple de code source suivant illustre une utilisation très basique de larandom
bibliothèque, en ce qui concerne @ question initiale Prévisibilité:Le moteur Mersenne Twister 32 bits , avec une distribution uniforme des valeurs entières , a été utilisé dans l'exemple ci-dessus. (Le nom du moteur dans le code source semble bizarre, car son nom vient de sa période de 2 ^ 19937-1). L'exemple utilise également
std::random_device
pour amorcer le moteur, qui obtient sa valeur du système d'exploitation (si vous utilisez un système Linux,std::random_device
renvoie une valeur à partir de/dev/urandom
).Prenez note que vous n'avez pas besoin d'utiliser
std::random_device
pour semer un moteur . Vous pouvez utiliser des constantes ou même lachrono
bibliothèque! Vous n'avez pas non plus besoin d'utiliser la version 32 bits dustd::mt19937
moteur, il existe d' autres options ! Pour plus d'informations sur les capacités de larandom
bibliothèque, veuillez consulter cplusplus.comDans l'ensemble, les programmeurs C ++ ne devraient plus utiliser
std::rand()
, non pas parce que c'est mauvais , mais parce que la norme actuelle offre de meilleures alternatives, plus simples et plus fiables . Espérons que beaucoup d'entre vous trouvent cela utile, en particulier ceux d'entre vous qui ont récemment effectué une recherche sur le Webgenerating random numbers in c++
!la source
Scénario de cas d'utilisation
J'ai comparé le problème de la prévisibilité à un sac de six morceaux de papier, chacun avec une valeur de 0 à 5 écrite dessus. Un morceau de papier est tiré du sac chaque fois qu'une nouvelle valeur est requise. Si le sac est vide, les numéros sont remis dans le sac.
... à partir de là, je peux créer une sorte d'algorithme.
Algorithme
Un sac est généralement un
Collection
. J'ai choisi unbool[]
(autrement connu sous le nom de tableau booléen, plan de bits ou carte de bits) pour prendre le rôle du sac.La raison pour laquelle j'ai choisi un
bool[]
est que l'index de chaque article est déjà la valeur de chaque morceau de papier. Si les papiers exigeaient autre chose, j'aurais utilisé unDictionary<string, bool>
à la place. La valeur booléenne est utilisée pour savoir si le numéro a déjà été dessiné ou non.Un compteur appelé
RemainingNumberCount
est initialisé à5
ce compte à rebours comme un nombre aléatoire est choisi. Cela nous évite d'avoir à compter le nombre de morceaux de papier qui restent chaque fois que nous souhaitons dessiner un nouveau nombre.Pour sélectionner la valeur aléatoire suivante, j'utilise a
for..loop
pour parcourir le sac d'index, et un compteur pour décompter quand unindex
estfalse
appeléNumberOfMoves
.NumberOfMoves
est utilisé pour choisir le prochain numéro disponible.NumberOfMoves
est d'abord défini comme une valeur aléatoire entre0
et5
, car il y a 0..5 étapes disponibles que nous pouvons faire à travers le sac. À l'itération suivante, la valeurNumberOfMoves
est définie au hasard entre0
et4
, car il y a maintenant 0..4 étapes que nous pouvons faire à travers le sac. Au fur et à mesure que les nombres sont utilisés, les nombres disponibles diminuent, nous utilisons doncrand() % (RemainingNumberCount + 1)
à la place pour calculer la valeur suivante pourNumberOfMoves
.Lorsque le
NumberOfMoves
compteur atteint zéro, lefor..loop
devrait comme suit:for..loop
de l'index.false
.for..loop
.Code
Le code de la solution ci-dessus est le suivant:
(placez les trois blocs suivants dans le fichier principal .cpp l'un après l'autre)
Une classe de console
Je crée cette classe Console car elle facilite la redirection de la sortie.
Ci-dessous dans le code ...
... peut être remplacé par ...
... et cette
Console
classe peut être supprimée si vous le souhaitez.Méthode principale
Exemple d'utilisation comme suit:
Exemple de sortie
Lorsque j'ai exécuté le programme, j'ai obtenu la sortie suivante:
Déclaration de clôture
Ce programme a été écrit en utilisant Visual Studio 2017 , et j'ai choisi d'en faire un
Visual C++ Windows Console Application
projet en utilisant.Net 4.6.1
.Je ne fais rien de particulièrement spécial ici, donc le code devrait également fonctionner sur les versions antérieures de Visual Studio.
la source
Voici une solution. Créez une fonction qui renvoie le nombre aléatoire et placez-la en dehors de la fonction principale pour la rendre globale. J'espère que cela t'aides
la source
Ce code produit des nombres aléatoires de
n
àm
.exemple:
la source
srand(time(0))
à la fonction principalerandom(n, m)
?srand(time(0))
à la fonction principale et non à la boucle for ou à l'intérieur de l'implémentation de la fonction.pour chaque fichier RUN au hasard
la source
Voici un générateur aléatoire simple avec env. probabilité égale de générer des valeurs positives et négatives autour de 0:
la source