Comment générer des flottants aléatoires en C ++?
Je pensais que je pouvais prendre le rand entier et le diviser par quelque chose, serait-ce suffisant?
c++
random
floating-point
hasen
la source
la source
random
tête ajouté en C ++ 11 est encore renforcé par le document standard N3924: Décourager rand () en C ++ 14 . J'inclusrand()
dans ma réponse pour des considérations principalement historiques, mais aussi pour réaliser que les anciennes applications existent.<random>
têteRéponses:
rand()
peut être utilisé pour générer des nombres pseudo-aléatoires en C ++. En combinaison avecRAND_MAX
et un peu de mathématiques, vous pouvez générer des nombres aléatoires dans n'importe quel intervalle arbitraire que vous choisissez. Ceci est suffisant pour des fins d'apprentissage et des programmes de jouets. Si vous avez besoin de nombres vraiment aléatoires avec une distribution normale, vous devrez utiliser une méthode plus avancée.Cela générera un nombre compris entre 0,0 et 1,0, inclus.
Cela va générer un certain nombre de 0,0 à un certain arbitraire
float
,X
:Cela générera un nombre de certains arbitraires
LO
à certains arbitrairesHI
:Notez que la
rand()
fonction ne sera souvent pas suffisante si vous avez besoin de nombres vraiment aléatoires.Avant d'appeler
rand()
, vous devez d'abord "amorcer" le générateur de nombres aléatoires en appelantsrand()
. Cela devrait être fait une fois pendant l'exécution de votre programme - pas une fois à chaque appelrand()
. Cela se fait souvent comme ceci:Pour appeler
rand
ousrand
vous devez#include <cstdlib>
.Pour appeler
time
, vous devez#include <ctime>
.la source
rand()
. Cette question, et ma réponse, était spécifiquement axée sur l'apprentissage des bases et n'était pas préoccupée par un degré élevé de précision. Vous devez apprendre à marcher avant de pouvoir courir.C ++ 11 vous offre de nombreuses nouvelles options avec
random
. L'article canonique sur ce sujet serait N3551, Génération de nombres aléatoires en C ++ 11Pour voir pourquoi l'utilisation
rand()
peut être problématique, voir le matériel de présentation rand () Considered Harmful de Stephan T. Lavavej donné lors de l' événement GoingNative 2013 . Les diapositives sont dans les commentaires mais voici un lien direct .Je couvre également
boost
ainsi que l'utilisationrand
car le code hérité peut encore nécessiter son support.L'exemple ci-dessous est distillé à partir du site cppreference et utilise le moteur std :: mersenne_twister_engine et le std :: uniform_real_distribution qui génère des nombres dans l'
[0,10)
intervalle, avec d'autres moteurs et distributions commentés ( voir en direct ):la sortie sera similaire à la suivante:
La sortie variera en fonction de la distribution que vous choisissez, donc si nous décidions d'aller avec std :: normal_distribution avec une valeur
2
à la fois pour la moyenne et stddev, par exemple,dist(2, 2)
la sortie serait similaire à ceci ( voir en direct ):Ce qui suit est une version modifiée d'une partie du code présenté dans
N3551
( voir en direct ):Les résultats ressembleront à:
Renforcer
Bien sûr, Boost.Random est toujours une option également, ici j'utilise boost :: random :: uniform_real_distribution :
rand()
Si vous devez utiliser
rand()
alors nous pouvons aller à la FAQ C pour un guide sur Comment puis-je générer des nombres aléatoires à virgule flottante? , qui donne essentiellement un exemple similaire à celui-ci pour générer un sur l'intervalle[0,1)
:et pour générer un nombre aléatoire dans la plage de
[M,N)
:la source
randMToN
pls? soit noter que c'est[M,N]
ou ajouter à+ 1.
partir de ce qui précèderandZeroToOne
. -> pensez à l'appeler comme ceci:randMToN(0.0, 1.0);
(N-M)
. Une bonne façon de traiter cette erreur se trouve ici: stackoverflow.com/questions/33058848/…Jetez un oeil à Boost.Random . Vous pouvez faire quelque chose comme ça:
Jouez, vous feriez mieux de passer le même objet mt19937 autour au lieu d'en construire un nouveau à chaque fois, mais j'espère que vous aurez l'idée.
la source
max
mais peut utiliser une composition non limitéemin
, vous pouvez inverser facilement l'intervalle:return min + max - gen();
.Dans la version moderne,
c++
vous pouvez utiliser l'en-<random>
tête fourni avecc++11
.Pour obtenir des statistiques aléatoires
float
, vous pouvez les utiliserstd::uniform_real_distribution<>
.Vous pouvez utiliser une fonction pour générer les nombres et si vous ne voulez pas que les nombres soient toujours les mêmes , définissez le moteur et la distribution
static
.Exemple:
Il est idéal de placer le
float
s dans un conteneur tel questd::vector
:Exemple de sortie:
la source
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
est techniquement incorrect, 1.0 ne sera jamais généré, voir en.cppreference.com/w/cpp/numeric/random/…To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Appelez le code avec deux
float
valeurs, le code fonctionne dans n'importe quelle plage.la source
fmaf()
(ou lafma()
surcharge flottante en C ++) en C99 ou C ++ 11, qui pourrait conserver plus de précision. Comme dansfmaf((float)rand() / RAND_MAX, b - a, a)
,.Si vous utilisez C ++ et non C, souvenez-vous que dans le rapport technique 1 (TR1) et dans le projet C ++ 0x, ils ont ajouté des fonctionnalités pour un générateur de nombres aléatoires dans le fichier d'en-tête, je pense qu'il est identique au Boost. Bibliothèque aléatoire et certainement plus flexible et "moderne" que la fonction de bibliothèque C, rand.
Cette syntaxe offre la possibilité de choisir un générateur (comme le mersenne twister mt19937) puis de choisir une distribution (normal, bernoulli, binomial etc.).
La syntaxe est la suivante (sans vergogne emprunté à ce site ):
la source
Sur certains systèmes (Windows avec VC vient à l'esprit, actuellement),
RAND_MAX
est ridiculement petit, i. e. seulement 15 bits. Lorsque vous divisez par,RAND_MAX
vous ne générez qu'une mantisse de 15 bits au lieu des 23 bits possibles. Cela peut ou non être un problème pour vous, mais vous manquez certaines valeurs dans ce cas.Oh, je viens de remarquer qu'il y avait déjà un commentaire pour ce problème. Quoi qu'il en soit, voici un code qui pourrait résoudre ce problème pour vous:
Non testé, mais pourrait fonctionner :-)
la source
drand48(3)
est la méthode standard POSIX. Glibc fournit également une version rentrante,drand48_r(3)
.La fonction a été déclarée obsolète dans SVID 3 mais aucune alternative adéquate n'a été fournie, donc IEEE Std 1003.1-2013 l' inclut toujours et n'a aucune note que cela va n'importe quand de sitôt.
Sous Windows, la méthode standard est CryptGenRandom () .
la source
Je n'ai été satisfait par aucune des réponses jusqu'à présent, j'ai donc écrit une nouvelle fonction flottante aléatoire. Il fait des hypothèses au niveau du bit sur le type de données float. Il a toujours besoin d'une fonction rand () avec au moins 15 bits aléatoires.
la source
À mon avis, la réponse ci-dessus donne un flottant «aléatoire», mais aucun d'entre eux n'est vraiment un flottant aléatoire (c'est-à-dire qu'il manque une partie de la représentation du flotteur). Avant de me précipiter dans mon implémentation, examinons d'abord le format standard ANSI / IEEE pour les flottants:
| signe (1 bit) | e (8 bits) | f (23 bits) |
le nombre représenté par ce mot est (-1 * signe) * 2 ^ e * 1.f
notez que le nombre «e» est un nombre biaisé (avec un biais de 127) allant de -127 à 126. La fonction la plus simple (et en fait la plus aléatoire) consiste à simplement écrire les données d'un int aléatoire dans un flottant, Donc
notez que si vous le faites,
float f = (float)rand();
il convertira l'entier en un flottant (ainsi 10 deviendra 10,0).Alors maintenant, si vous voulez limiter la valeur maximale, vous pouvez faire quelque chose comme (je ne sais pas si cela fonctionne)
mais si vous regardez la structure du flotteur, vous pouvez voir que la valeur maximale d'un flotteur est (environ) 2 ^ 127 qui est beaucoup plus grande que la valeur maximale d'un int (2 ^ 32) excluant ainsi une partie importante de les nombres qui peuvent être représentés par un flotteur. Ceci est ma mise en œuvre finale:
l'utilisation de cette fonction
randf(0, 8, 0)
renvoie un nombre aléatoire compris entre 0,0 et 255,0la source
int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
et la mantisse:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
remplacer leurs lignes respectives ci-dessus. Notez que l'erreur de mantisse est majeure: pour lesRAND_MAX
plus petits,1 << 23
vous ne randomisez que les bits de poids faible et obtenez tout le temps les 0 pour les bits de poids fort!Si vous savez que votre format à virgule flottante est IEEE 754 (presque tous les processeurs modernes, y compris Intel et ARM), vous pouvez créer un nombre à virgule flottante aléatoire à partir d'un entier aléatoire à l'aide de méthodes binaires. Cela ne doit être pris en compte que si vous n'avez pas accès aux C ++ 11
random
ouBoost.Random
qui sont tous les deux bien meilleurs.Cela donnera une meilleure distribution que celle utilisant la division.
la source
return (float)random23 / (1 << 23)
. (Oui, je viens de tester cela , en modifiant votre fonction pour prendrerandom32
en paramètre et en l'exécutant pour toutes les valeurs de zéro à(1 << 23)-1
. Et oui, votre méthode donne en effet exactement les mêmes résultats que la division par1 << 23
.)Pour C ++, il peut générer de vrais nombres flottants dans la plage spécifiée par la
dist
variablela source
rand () retourne un int entre 0 et RAND_MAX. Pour obtenir un nombre aléatoire entre 0,0 et 1,0, commencez par convertir le retour int par rand () en un flottant, puis divisez par RAND_MAX.
la source
Je n'ai pas pu poster deux réponses, voici donc la deuxième solution. log2 nombres aléatoires, biais massif vers 0,0f mais c'est vraiment un flottant aléatoire de 1,0f à 0,0f.
la source