Comment puis-je générer un nombre aléatoire en utilisant la bibliothèque standard C++11

la nouvelle norme C++11 a un chapitre entier dédié aux générateurs de nombres aléatoires. Mais comment puis-je effectuer la tâche la plus simple, la plus courante qui était codée comme ceci, mais sans recourir à la bibliothèque standard C:

srand((unsigned int)time(0));
int i = rand();

y a-t-il des valeurs par défaut raisonnables pour les moteurs à nombres aléatoires, les distributions et les graines que l'on pourrait utiliser à l'extérieur de la boîte?

23
demandé sur Raedwald 2011-08-28 02:28:08

7 réponses

Vous devriez être en mesure de faire quelque chose comme:

std::default_random_engine e((unsigned int)time(0));
int i = e();

La qualité de l' default_random_engine est dépendant de l'implémentation. Vous pouvez également utiliser std::min_rand0 ou std::min_rand.

Probablement une meilleure façon de graine aléatoire moteur avec comme vrai un nombre aléatoire de la mise en œuvre plutôt que d'utiliser time.

E. G.

std::random_device rd;
std::default_random_engine e( rd() );
30
répondu CB Bailey 2011-08-27 23:33:28

unifier et simplifier certains des exemples déjà fournis je résumerai à:

// Good random seed, good engine
auto rnd1 = std::mt19937(std::random_device{}());

// Good random seed, default engine
auto rnd2 = std::default_random_engine(std::random_device{}());

// like rnd1, but force distribution to int32_t range
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));

// like rnd3, but force distribution across negative numbers as well
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

puis j'ai fait quelques tests pour voir à quoi ressemblent les valeurs par défaut:

#include <random>
#include <functional>
#include <limits>
#include <iostream>

template<class Func>
void print_min_mean_max(Func f) {
   typedef decltype(f()) ret_t;
   ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min();
   uint64_t total = 0, count = 10000000;
   for (uint64_t i = 0; i < count; ++i) {
      auto res = f();
      min = std::min(min,res);
      max = std::max(max,res);
      total += res;
   }
   std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl;
}

int main() {
   auto rnd1 = std::mt19937(std::random_device{}());
   auto rnd2 = std::default_random_engine(std::random_device{}());

   auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
   auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

   print_min_mean_max(rnd1);
   print_min_mean_max(rnd2);
   print_min_mean_max(rnd3);
   print_min_mean_max(rnd4);
}

produit la sortie:

min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978

comme nous pouvons le voir, mt19937 et default_random_engine ont une portée par défaut différente, donc l'utilisation de uniform_int_distribution est conseillée.

en outre, uniform_int_distribution par défaut est [0, max_int] (non-négatif), même en utilisant une signature type entier. Doit fournir la portée explicitement si vous voulez la portée complète.

Enfin, il est important de s'en souvenir dans des moments comme ceux-ci.

6
répondu mmocny 2013-02-01 03:30:28

si votre code existant était approprié avant la nouvelle norme, alors il le restera. Les nouveaux générateurs de nombres aléatoires ont été ajoutés pour les applications qui nécessitent une qualité supérieure de pseudo-aléatoire, par exemple la simulation stochastique.

2
répondu David Heffernan 2011-08-27 22:46:01

j'utilise le code suivant dans mon projet. 'moteur' et' distribution ' peuvent être l'un des fournis par la bibliothèque.

#include <random>
#include <functional>
#include <iostream>
...
std::uniform_int_distribution<unsigned int> unif;
std::random_device rd;
std::mt19937 engine(rd());
std::function<unsigned int()> rnd = std::bind(unif, engine);

std::cout << rnd() << '\n';
2
répondu dimitri 2011-08-28 07:09:52

Ici vous allez. Doublures aléatoires dans une gamme:

// For ints
// replace _real_ with _int_, 
// <double> with <int> and use integer constants

#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>

int main()
{
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100);  //(min, max)

    //get one
    const double random_num = dist(rng);

    //or..
    //print 10 of them, for fun.
    std::generate_n( 
        std::ostream_iterator<double>(std::cout, "\n"), 
        10, 
        [&]{ return dist(rng);} ); 
    return 0;
}
2
répondu Carl 2013-02-01 04:01:22

la génération de nombres aléatoires est un problème difficile. Il n'est pas vraiment aléatoire façon de le faire. Si vous générez juste de l'aléatoire pour semer un environnement de jeu alors votre approche devrait être très bien. rand () présente plusieurs lacunes.

si vous avez besoin de randomness pour générer des clés de cryptage, alors vous êtes sol.la meilleure façon dans ce cas est d'Aller vers le système d'exploitation, qui a habituellement mécanisme. Sur POSIX qui est de l'aléatoire() (ou lire à partir de /dev/random, si vous êtes dans la même disposition). Sur Windows vous pouvez utiliser le CryptoAPI:

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

0
répondu Adam Hawes 2011-08-27 23:56:44

vous pouvez utiliser RC4 pour générer des octets aléatoires. Il a probablement les propriétés que vous voulez. Il est rapide et assez simple à mettre en œuvre. La séquence est reproductible dans toutes les implémentations lorsque la graine est connue, et complètement imprévisible lorsque la graine n'est pas connue. http://en.wikipedia.org/wiki/RC4

0
répondu Matt Mahoney 2011-08-28 00:25:42