Comment générer de façon aléatoire un int en C?
Est-il une fonction pour générer un random int nombre en C? Ou devrai-je utiliser un tiers de la bibliothèque?
- Sujet de Long en comp.lang.c sur rand() et PRNG "qualité".
- Voir aussi
srand
: pourquoi l'appeler qu'une seule fois.
Vous devez vous connecter pour publier un commentaire.
Modifier: Sur Linux, vous pourriez préférer utiliser aléatoire et srandom.
time()
change seulement une fois par seconde. Si vous avez des graines detime()
, pour chaque appel àrand()
, alors vous obtiendrez la même valeur pour chaque appel pendant une seule seconde. Mais la plus grande raison est que les propriétés derand()
et des fonctions comme il sont connu pour le cas où ils sont ensemencées exactement une fois par série, et non pas sur chaque seul appel. Fonction "aléatoire" avec non testés ou non prouvées propriétés conduit à des problèmes.rand()
au lieu detime()
?rand()
est souvent le cas) semis avecrand()
, au mieux, ont plus aucun effet, et, au pire, de casser le générateur de qualités sont connues. C'est un profond sujet. Commencer avec la lecture de Knuth Vol 2 le Chapitre 3 sur les nombres aléatoires comme la meilleure introduction aux mathématiques et des pièges.time()
et transmis variable sera remplacé à l'heure actuelle.srand((unsigned int)time(NULL));
guessing game.c:6:12: error: expected ')'
time()
de semences si votre programme a une chance d'être exécuté deux fois ou plus au cours d'une seconde (ce qui est susceptible de se produire si elle est appelée à partir d'un scripts bash). Sauver les semences dans un fichier à la place.random
etsrandom
- comme recommandé par l'homme pagesrandom()
etsrandom()
sont glibc spécifiques et ne semble pas exister dansstdlib.h
par exemple, sur windows. La question était de pas spécifique à linux.La
rand()
fonction dans<stdlib.h>
renvoie une pseudo-aléatoire entier compris entre 0 etRAND_MAX
. Vous pouvez utilisersrand(unsigned int seed)
pour définir une graine.Il est de pratique courante d'utiliser les
%
opérateur en conjonction avecrand()
pour obtenir une autre gamme (bien garder à l'esprit que cela déclenche l'uniformité un peu). Par exemple:Si vous vraiment de soins au sujet de l'uniformité, vous pouvez faire quelque chose comme ceci:
%
est l'opérateur de modulo. Il vous donne le reste d'une division entière, de sortex % n
toujours de vous donner un nombre entre0
etn - 1
(tant quex
etn
sont à la fois positives). Si vous trouvez encore que de la confusion, essayez d'écrire un programme qui ai
compter de 0 à 100, et imprimei % n
pour certainsn
de votre choix plus petit que 100.rand()%5
signifie que 0 se fera 858993460/858993459 fois plus souvent que 4. Par rapport aux autres défauts de aucun utilisation derand()
, je considère que trivial. Une raison de plus (à mon avis) pour raillerrand()%n
est que les bits de bas derand()
séquence ont une réputation pour la répétition avec une période beaucoup plus courte que les bits de poids fort, donc sin
est une puissance de 2, vous pouvez obtenir un étonnant modèle dans tout ce que vous utilisez ce pour.RAND_MAX
, qui peut être aussi bas que 32767. Encore, je suis d'accord avec votre point de que la non-uniformité est assez insignifiant pour la plupart des applications. La qualité du GÉNÉRATEUR est également fortement la mise en œuvre spécifique. Si vous avez besoin de haute qualité de nombres aléatoires, vous ne devriez pas être à l'aide derand()
.rand()
pour rien là où cela compte vraiment.randint(n)
fonction est clairement rompu pourn=1
. Il doit produire des résultats comme à pile ou face, mais il produit tous les zéros, jusqu'à présent.randint(2)
. Ceci est également cohérent avec la façon dont%
se comporte.long
, mais probablement eu quelque chose à voir avec ce que se multiplier. J'ai mis à jour la réponse.Si vous avez besoin de sécuriser des caractères aléatoires ou des entiers:
Comme il en est question dans comment en toute sécurité générer des nombres aléatoires dans divers langages de programmation, vous aurez envie de faire l'une des opérations suivantes:
randombytes
API/dev/urandom
, pas/dev/random
. Pas OpenSSL (ou un autre utilisateur PRNGs).Par exemple:
randombytes_uniform()
est cryptographique sécurisé et impartiale.sodium_init()
à un certain point. Ne vous inquiétez pas au sujet de la RNG, il utilise le noyau.sodium_init()
même si ce n'est pas forcément une partie de mon exemple parce que c'est un détail important.Permet de passer à travers cela. Nous avons d'abord utiliser le srand() la fonction de semences de l'aléatoire. Fondamentalement, l'ordinateur peut générer des nombres aléatoires sur la base du nombre qui est alimenté à srand(). Si vous vous êtes donné la même valeur de départ, puis les mêmes nombres aléatoires générées à chaque fois.
Par conséquent, nous avons à la graine aléatoire avec une valeur qui est toujours en train de changer. Nous le faisons en le nourrissant à la valeur de l'heure actuelle avec la fonction time ().
Maintenant, quand nous appelons rand(), un nouveau nombre aléatoire sera produit à chaque fois.
else{ low_num=max_num; hi_num=min_num+1;
2) échoue lorsquehi_num - low_num > INT_MAX
. 3) Omet les valeurs dans la situation rareINT_MAX > hi_num - low_num > RAND_MAX
.(rand()%(hi_num-low_num))+low_num
hi_num = max_num + 1;
manque de protection contre le débordement.RAND_MAX == INT_MAX
.RAND_MAX
peut être aussi petit que 32767 même avec un 4 octetsint
. De plus,hi_num - low_num
peut facilement déborder.Si vous avez besoin d'une meilleure qualité de l'pseudo-aléatoire de nombres que ce
stdlib
offre, découvrez Mersenne Twister. C'est plus rapide, trop. Exemple implémentations sont nombreux, par exemple ici.La norme fonction C est
rand()
. C'est assez bon pour traiter les cartes de solitaire, mais c'est horrible. De nombreuses implémentations derand()
cycle au moyen d'une courte liste de nombres, et les bits de poids faible ont des cycles plus courts. La façon que certains programmes d'appelrand()
est terrible, et le calcul d'une bonne semence de passer àsrand()
est dur.La meilleure façon de générer des nombres aléatoires en C, c'est d'utiliser une bibliothèque tierce, comme OpenSSL. Par exemple,
Pourquoi autant de code? D'autres langages comme Java et Ruby ont des fonctions aléatoires entiers ou des flotteurs. OpenSSL ne donne que des octets aléatoires, donc j'essaie d'imiter la façon dont Java ou Ruby serait de les transformer en nombres entiers ou des flotteurs.
Pour les entiers, nous voulons éviter modulo biais. Supposons que nous avons eu quelques aléatoire à 4 chiffres entiers de
rand() % 10000
, maisrand()
ne peut retourner 0 à 32767 (comme il le fait dans Microsoft Windows). Chaque nombre de 0 à 2767 apparaît plus souvent que chaque numéro de 2768 à 9999. Pour supprimer les biais, on peut réessayerrand()
alors que la valeur est en dessous de 2768, parce que les 30000 valeurs de 2768 à 32767 carte uniformément sur les 10000 valeurs de 0 à 9999.Pour des flotteurs, nous voulons 53 bits aléatoires, car un
double
détient 53 bits de précision (en supposant que c'est une norme IEEE double). Si nous utilisons plus de 53 bits, on obtient l'arrondissement de biais. Certains programmeurs d'écrire du code commerand() /(double)RAND_MAX
, maisrand()
pourrait revenir seulement 31 bits, ou seulement 15 bits dans Windows.OpenSSL est
RAND_bytes()
graines de lui-même, peut-être par la lecture de/dev/urandom
dans Linux. Si nous avons besoin de beaucoup de nombres aléatoires, ce serait trop lent pour lire à partir d'/dev/urandom
, parce qu'ils doivent être copiés à partir du noyau. Il est plus rapide pour permettre OpenSSL pour générer plus de nombres aléatoires à partir d'une graine.Plus à propos de nombres aléatoires:
srand()
. Il mélange les bits de l'heure actuelle, l'ID de processus, et de quelques conseils, si il ne peut pas lire/dev/urandom
.float
/double
, donc j'ai clarifié la question de coller àint
numéros pour éviter d'en faire trop large. Il y a d'autres questions qui traitent spécifiquement de lafloat
/double
valeurs aléatoires, de sorte que vous pouvez reposter votre deuxième moitié de votre réponse à des questions telles que stackoverflow.com/questions/13408990/...Si votre système prend en charge la
arc4random
famille de fonctions je recommande l'utilisation de ceux-ci au lieu de la normerand
fonction.La
arc4random
famille comprend:arc4random
rendements aléatoires de 32 bits non signés.arc4random_buf
met aléatoire contenu du paramètrebuf : void *
. La quantité de contenu est déterminé par lebytes : size_t
paramètre.arc4random_uniform
retourne un hasard non signé de 32 bits nombre entier qui suit la règle:0 <= arc4random_uniform(limit) < limit
, où la limite est aussi un entier 32 bits non signé.arc4random_stir
lit les données à partir/dev/urandom
et transmet les données àarc4random_addrandom
en plus aléatoire interne de nombre aléatoire piscine.arc4random_addrandom
est utilisé pararc4random_stir
à remplir interne de nombre aléatoire de la piscine selon les données transmises.Si vous ne disposez pas de ces fonctions, mais vous êtes sous Unix, vous pouvez utiliser ce code:
La
urandom_init
fonction ouvre le/dev/urandom
appareil, et met le descripteur de fichier dansurandom_fd
.La
urandom
fonction est essentiellement le même comme un appel àrand
, sauf le plus sécurisé, et il renvoie unlong
(facilement modifiable).Cependant,
/dev/urandom
peut être un peu lent, il est donc recommandé de l'utiliser comme une graine pour un autre générateur de nombre aléatoire.Si votre système ne dispose pas de
/dev/urandom
, mais ne ont un/dev/random
ou d'un fichier similaire, alors vous pouvez simplement modifier le chemin d'accès transmis àopen
dansurandom_init
. Les appels et les Api utilisées dansurandom_init
eturandom
sont (je crois) conforme à POSIX, et en tant que tel, devrait fonctionner sur la plupart, si pas tous conformes à POSIX systèmes.Notes: Une lecture à partir d'
/dev/urandom
ne bloquera PAS si il y a insuffisance de l'entropie disponible, de sorte que les valeurs générées dans de telles circonstances peut être chiffrée de manière précaire. Si vous êtes inquiet à ce sujet, puis utilisez/dev/random
, qui vous permettra de toujours bloquer si il est insuffisant de l'entropie.Si vous êtes sur un autre système(Windows), puis utilisez
rand
ou certaines Fenêtres internes spécifiques à la plate-forme dépendante non-portable API.Fonction Wrapper pour
urandom
,rand
, ouarc4random
appels:STL n'existe pas en C. Vous devez appeler
rand
, ou mieux encore,random
. Elles sont déclarées dans la bibliothèque standard de l'en-têtestdlib.h
.rand
est POSIX,random
est un BSD spec fonction.La différence entre
rand
etrandom
est querandom
renvoie beaucoup plus utilisable 32 bits nombre aléatoire, etrand
renvoie généralement un nombre sur 16 bit. Le BSD pages de manuel montrent que les bits de poids faible derand
sont cyclique et prévisible, de sorterand
est potentiellement inutiles pour les petits nombres.extern int rand(void);
etextern void srand(unsigned int);
.Ont un coup d'oeil à ISAAC (Indirection, de Décalage, d'Accumuler, d'Ajouter et de Comptage). Ses réparties uniformément et a une durée moyenne de cycle de 2^8295.
C'est un bon moyen pour obtenir un nombre aléatoire entre deux numéros de votre choix.
La sortie de la première heure: 39
La sortie de la seconde heure: 61
De sortie pour la troisième fois: 65
Vous pouvez modifier les valeurs après
randnum
à ce que les numéros que vous choisissez, et il va générer un nombre aléatoire entre ces deux nombres.Vous souhaitez utiliser
rand()
. Note (TRÈS IMPORTANT): assurez-vous que la graine pour la fonction rand. Si vous ne le faites pas, vos nombres aléatoires sont pas vraiment au hasard. C'est très, très, très important. Heureusement, vous pouvez généralement utiliser une combinaison du système de tiques de la minuterie et de la date pour obtenir une bonne semence.FWIW, la réponse est que oui, il y a un
stdlib.h
fonction appeléerand
; cette fonction est réglée principalement pour la vitesse et de la distribution, pas pour de l'imprévisibilité. Presque tous les intégrés dans les fonctions aléatoires de diverses langues et des cadres de l'utilisation de cette fonction par défaut. Il y a aussi "cryptographique" générateurs de nombres aléatoires qui sont beaucoup moins prévisibles, mais beaucoup plus lentement. Elles devraient être utilisées dans toute sorte de sécurité liées à l'application.C'est je l'espère un peu plus aléatoire que de simplement en utilisant
srand(time(NULL))
.srand(rand());
! Ingénieux!Bien, STL C++, pas du C, donc je ne sais pas ce que vous voulez. Si vous voulez C, cependant, il est la
rand()
etsrand()
fonctions:Ce sont à la fois partie de la norme ANSI C. Il y a aussi le
random()
fonction:Mais aussi loin que je peux dire,
random()
n'est pas la norme ANSI C. Une bibliothèque tierce, peut-être pas une mauvaise idée, mais tout dépend de l'aléatoire d'un numéro que vous avez vraiment besoin de générer.C Programme générateur de nombre aléatoire entre 9 et 50
En général, nous pouvons générer un nombre aléatoire entre lowerLimit et upperLimit-1
je.e lowerLimit est inclusif ou dire r ∈ [ lowerLimit, upperLimit )
rand()
est le moyen le plus pratique pour générer des nombres aléatoires.Vous pouvez également assister à un nombre aléatoire à partir de n'importe quel service en ligne comme random.org.
a
etb
.rand
.Moderne Processeurs x86_64 vous pouvez utiliser le matériel générateur de nombre aléatoire via
_rdrand64_step()
Exemple de code:
Audience une bonne explication de pourquoi à l'aide de
rand()
pour produire de l'aléatoire uniformément distribué des nombres dans une plage donnée est une mauvaise idée, j'ai décidé de prendre un coup d'oeil à la façon biaisée, la sortie est en réalité. Mon cas de test était juste de dés à jeter. Voici le code C:et voici sa sortie:
Je ne sais pas comment uniforme vous avez besoin de vos nombres aléatoires, mais le ci-dessus apparaît uniforme suffisant pour la plupart des besoins.
Edit: ce serait une bonne idée pour initialiser le GÉNÉRATEUR avec quelque chose de mieux que
time(NULL)
.J'ai eu un sérieux problème avec le générateur de nombre pseudo-aléatoire, dans mon application récente: je repeatidly appelé mon programme C par l'intermédiaire d'un pyhton script et j'ai été en utilisant comme semence, le code suivant:
Cependant, depuis:
man srand
);time
reviendra de la même valeur à chaque fois.Mon programme a généré la même séquence de nombres.
Vous pouvez faire 3 choses pour résoudre ce problème:
mélange temps de sortie avec quelques autres informations modification sur les pistes (dans mon application, le nom de la sortie):
J'ai utilisé djb2 que ma fonction de hachage.
Augmenter le temps de résolution. Sur ma plate-forme,
clock_gettime
était disponible, j'ai donc l'utiliser:Utiliser les deux méthodes ensemble:
Option 3 vous assure (autant que je sache), le mieux est de semences randomity, mais il peut créer une différence de seulement très rapide de l'application.
À mon avis, l'option 2 est un pari sûr.
En dépit de toutes les personnes suggestion
rand()
ici, vous ne voulez pas utiliserrand()
, sauf si vous avez! Les numéros aléatoires quirand()
produit sont souvent très mauvais. Pour citer le Linux homme page:Concernant la portabilité,
random()
est aussi défini par la norme POSIX pour un certain temps maintenant.rand()
est vieux, il est apparu déjà dans la première POSIX.1 spec (IEEE Std 1003.1-1988), alors querandom()
est d'abord apparu dans POSIX.1-2001 (IEEE Std 1003.1-2001), et pourtant le standard POSIX est déjà POSIX.1-2008 date (IEEE Std 1003.1-2008), qui a reçu une mise à jour, il y a un an (IEEE Std 1003.1-2008, 2016 Édition). Donc je ne considèrerandom()
être très portable.POSIX.1-2001 a également introduit le
lrand48()
etmrand48()
fonctions, voir ici:Et un assez bon pseudo-aléatoire de la source est le
arc4random()
fonction qui est disponible sur de nombreux systèmes. Pas partie d'une norme officielle, est apparue dans BSD autour de 1997, mais vous pouvez le trouver sur des systèmes comme Linux et macOS/iOS.Mon minimaliste solution qui devrait fonctionner pour les nombres aléatoires dans la gamme
[min, max)
. Utilisationsrand(time(NULL))
avant d'appeler la fonction.Essayer cela, je l'ai mis ensemble à partir de certains des concepts déjà référencé ci-dessus:
srand()
chaque fois que vous voulez l'appelerrand()
est une idée terrible. Depuistime()
renvoie généralement une valeur dans secondes l'appel de cette fonction rapidement reviendra de la même "aléatoire" de la valeur.random()
fonction.