generar números dobles aleatorios en c ++

83

Cómo generar números aleatorios entre dos dobles en c ++, estos números deben verse como xxxxx, yyyyy.

Radi
fuente
6
"este número debería verse como xxxxx, yyyyy". Cómo generar dobles aleatorios y cómo formatear dobles como cadenas son cuestiones completamente independientes.
Steve Jessop
Y ahora que lo pienso de manera alternativa: generar dobles distribuidos uniformemente y generar decimales distribuidos uniformemente son tareas algo diferentes, aunque relacionadas.
Steve Jessop
La generación de enteros distribuidos uniformemente está más estrechamente relacionada con el problema de los decimales.
Potatoswatter

Respuestas:

116

Así es cómo

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

Recuerde llamar a srand () con una semilla adecuada cada vez que se inicie su programa.

[Editar] Esta respuesta es obsoleta ya que C ++ obtuvo su biblioteca aleatoria nativa no basada en C (vea la respuesta de Alessandro Jacopson) Pero, esto todavía se aplica a C

rep_movsd
fuente
10
Si agrega 1 a RAND_MAX, hágalo con cuidado, ya que podría ser igual a INT_MAX. double f = rand() / (RAND_MAX + 1.0);
Steve Jessop
8
Tenga en cuenta que la aleatoriedad de esto puede ser limitada. El rango xxxxx, yyyyy sugiere 10 dígitos decimales. Hay muchos sistemas en los que RAND_MAX es menor que 10 ^ 10. Esto significaría que algunos números en ese rango tienenp(xxxxx,yyyyy)==0.0
MSalters
7
Debe evitar rand () si es posible. Vea la otra respuesta para una solución C ++ 11 o TR1.
jfritz42
No todo el mundo usa C ++ 0x, tr1 o C ++ 11 ¿Hay alguna referencia que muestre que debe evitarse rand ()? Ha sido la única forma de obtener números aleatorios durante décadas.
rep_movsd
1
@ChamilaWijayarathna, debe incluir cstdlib
Veridian
103

Esta solución requiere C ++ 11 (o 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;
}

Para obtener más detalles, consulte "Generación de números aleatorios usando C ++ TR1" de John D. Cook .

Ver también Stroustrup's "Generación de números aleatorios" .

Alessandro Jacopson
fuente
7
Es posible que desee actualizar esto con un documento cppreference más reciente , que es bastante bueno.
Shafik Yaghmour
10

Debe ser eficiente, seguro para subprocesos y lo suficientemente flexible para muchos usos:

#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';
}
Galik
fuente
7

Si la precisión es un problema aquí, puede crear números aleatorios con una graduación más fina aleatorizando los bits significativos. Supongamos que queremos tener un doble entre 0.0 y 1000.0.

En MSVC (12 / Win32) RAND_MAX es 32767, por ejemplo.

Si usa el rand()/RAND_MAXesquema común , sus brechas serán tan grandes como

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

En el caso de IEE 754 variables dobles (53 bits significativos) y aleatorización de 53 bits, la brecha de aleatorización más pequeña posible para el problema de 0 a 1000 será

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

y por lo tanto significativamente más bajo.

La desventaja es que se necesitarán 4 llamadas rand () para obtener el número entero aleatorio (asumiendo un RNG de 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 se desconoce el número de bits para la mantisa o el RNG, es necesario obtener los valores respectivos dentro de la función.

#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);
}

Nota: No sé si el número de bits para unsigned long long (64 bits) es mayor que el número de bits de doble mantisa (53 bits para IEE 754) en todas las plataformas o no. Probablemente sería "inteligente" incluir un cheque como if (sizeof(unsigned long long)*8 > num_mant_bits) ...si este no fuera el caso.

Pixelchemist
fuente
3

Este fragmento es directamente de The C ++ Programming Language (cuarta edición) de Stroustrup, §40.7; requiere 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;
}
Alessandro Jacopson
fuente
0

algo como esto:

#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;
}
Oleg Razgulyaev
fuente
2
"(random ()% max_rand)" = "random ()" (es decir, 3% 7 = 3). Este sería un paso de procesamiento en vano.
Zak