web-dev-qa-db-fra.com

générer des nombres doubles aléatoires en c ++

Comment générer des nombres aléatoires entre deux doubles en c ++, ces nombres doivent ressembler à xxxxx, yyyyy.

73
Radi

Voici comment

double fRand(double fMin, double fMax)
{
    double f = (double)Rand() / Rand_MAX;
    return fMin + f * (fMax - fMin);
}

N'oubliez pas d'appeler srand () avec une graine appropriée à chaque démarrage du programme.

[Edit] Cette réponse est obsolète car C++ a sa bibliothèque aléatoire native non basée sur C (voir la réponse de Alessandro Jacopsons). Mais cela s'applique toujours à C

103
rep_movsd

Cette solution nécessite C++ 11 (ou TR1).

#include <random>

int main()
{
   double lower_bound = 0;
   double upper_bound = 10000;
   std::uniform_real_distribution<double> unif(lower_bound,upper_bound);
   std::default_random_engine re;
   double a_random_double = unif(re);

   return 0;
}

Pour plus de détails, voir John D. Cook's "Génération de nombres aléatoires à l'aide de C++ TR1" .

Voir aussi Stroustrup's "Génération de nombres aléatoires" .

85
Alessandro Jacopson

Si la précision est un problème ici, vous pouvez créer des nombres aléatoires avec une graduation plus fine en randomisant les bits significatifs. Supposons que nous voulions avoir un double entre 0.0 et 1000.0.

Sur MSVC (12/Win32), Rand_MAX est 32767 par exemple.

Si vous utilisez le schéma commun Rand()/Rand_MAX, vos espaces seront aussi grands que

1.0 / 32767.0 * ( 1000.0 - 0.0) = 0.0305 ...

Dans le cas de variables IEE 754 doubles (53 bits significatifs) et de randomisation à 53 bits, le plus petit écart de randomisation possible pour le problème de 0 à 1000 sera

2^-53 * (1000.0 - 0.0) = 1.110e-13

et donc significativement plus bas.

L'inconvénient est que 4 appels Rand () seront nécessaires pour obtenir le nombre entier aléatoire (en supposant un RNG 15 bits).

double random_range (double const range_min, double const range_max)
{
  static unsigned long long const mant_mask53(9007199254740991);
  static double const i_to_d53(1.0/9007199254740992.0);
  unsigned long long const r( (unsigned long long(Rand()) | (unsigned long long(Rand()) << 15) | (unsigned long long(Rand()) << 30) | (unsigned long long(Rand()) << 45)) & mant_mask53 );
  return range_min + i_to_d53*double(r)*(range_max-range_min);
}

Si le nombre de bits pour la mantisse ou le RNG est inconnu, vous devez obtenir les valeurs respectives dans la fonction.

#include <limits>
using namespace std;
double random_range_p (double const range_min, double const range_max)
{
  static unsigned long long const num_mant_bits(numeric_limits<double>::digits), ll_one(1), 
    mant_limit(ll_one << num_mant_bits);
  static double const i_to_d(1.0/double(mant_limit));
  static size_t num_Rand_calls, rng_bits;
  if (num_Rand_calls == 0 || rng_bits == 0)
  {
    size_t const Rand_max(Rand_MAX), one(1);
    while (Rand_max > (one << rng_bits))
    {
      ++rng_bits;
    }
    num_Rand_calls = size_t(ceil(double(num_mant_bits)/double(rng_bits)));
  }
  unsigned long long r(0);
  for (size_t i=0; i<num_Rand_calls; ++i)
  {
    r |= (unsigned long long(Rand()) << (i*rng_bits));
  }
  r = r & (mant_limit-ll_one);
  return range_min + i_to_d*double(r)*(range_max-range_min);
}

Remarque: je ne sais pas si le nombre de bits pour unsigned long long (64 bits) est supérieur au nombre de bits de double mantisse (53 bits pour IEE 754) sur toutes les plates-formes ou non. Il serait probablement "intelligent" d'inclure une vérification comme if (sizeof(unsigned long long)*8 > num_mant_bits) ... si ce n'est pas le cas.

7
Pixelchemist

Cela doit être performant, thread-safe et suffisamment flexible pour de nombreuses utilisations:

#include <random>
#include <iostream>

template<typename Numeric, typename Generator = std::mt19937>
Numeric random(Numeric from, Numeric to)
{
    thread_local static Generator gen(std::random_device{}());

    using dist_type = typename std::conditional
    <
        std::is_integral<Numeric>::value
        , std::uniform_int_distribution<Numeric>
        , std::uniform_real_distribution<Numeric>
    >::type;

    thread_local static dist_type dist;

    return dist(gen, typename dist_type::param_type{from, to});
}

int main(int, char*[])
{
    for(auto i = 0U; i < 20; ++i)
        std::cout << random<double>(0.0, 0.3) << '\n';
}
7
Galik

Cet extrait provient directement de Stroustrup Le langage de programmation C++ (4ème édition) , §40.7; il nécessite C++ 11:

#include <functional>
#include <random>

class Rand_double
{
public:
    Rand_double(double low, double high)
    :r(std::bind(std::uniform_real_distribution<>(low,high),std::default_random_engine())){}

    double operator()(){ return r(); }

private:
    std::function<double()> r;
};

#include <iostream>    
int main() {
    // create the random number generator:
    Rand_double rd{0,0.5};

    // print 10 random number between 0 and 0.5
    for (int i=0;i<10;++i){
        std::cout << rd() << ' ';
    }
    return 0;
}
2

quelque chose comme ça:

#include <iostream>
#include <time.h>

using namespace std;

int main()
{
    const long max_Rand = 1000000L;
    double x1 = 12.33, x2 = 34.123, x;

    srandom(time(NULL));

    x = x1 + ( x2 - x1) * (random() % max_Rand) / max_Rand;

    cout << x1 << " <= " << x << " <= " << x2 << endl;

    return 0;
}
0
Oleg Razgulyaev