generuje losowe liczby podwójne w języku c ++


83

Jak wygenerować liczby losowe między dwoma podwójnymi w c ++, te liczby powinny wyglądać jak xxxxx, yyyyy.


6
„numer ten powinien wyglądać następująco: xxxxx, yyyyy”. Jak generować losowe liczby podwójne i jak formatować jedynki jako ciągi, to zupełnie odrębne kwestie.
Steve Jessop

I pomyśl o tym alternatywnie: generowanie równo rozłożonych podwójnych i generowanie równomiernie rozłożonych liczb dziesiętnych to nieco inne, choć powiązane, zadania.
Steve Jessop

Generowanie liczb całkowitych o równomiernym rozkładzie jest ściślej związane z problemem ułamków dziesiętnych.
Potatoswatter

Odpowiedzi:


116

Oto jak

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

Pamiętaj, aby wywołać srand () z odpowiednim ziarnem za każdym razem, gdy program zostanie uruchomiony.

[Edytuj] Ta odpowiedź jest przestarzała, ponieważ C ++ ma swoją natywną, losową bibliotekę nie opartą na C (zobacz odpowiedź Alessandro Jacopsona) Ale to nadal dotyczy C


10
Jeśli dodasz 1 do RAND_MAX, zrób to ostrożnie, ponieważ może być równe INT_MAX. double f = rand() / (RAND_MAX + 1.0);
Steve Jessop

8
Zauważ, że losowość tego może być ograniczona. Zakres xxxxx, yyyyy sugeruje 10 cyfr dziesiętnych. Istnieje wiele systemów, w których RAND_MAX jest mniejszy niż 10 ^ 10. Oznaczałoby to, że niektóre liczby z tego zakresu mająp(xxxxx,yyyyy)==0.0
MSalters

7
Jeśli to możliwe, powinieneś unikać rand (). Zobacz inną odpowiedź dla rozwiązania C ++ 11 lub TR1.
jfritz42,

Nie wszyscy używają C ++ 0x, tr1 lub C ++ 11 Czy jest jakieś odniesienie, które pokazuje, że rand () należy unikać? To był jedyny sposób na uzyskanie liczb losowych od dziesięcioleci.
rep_movsd,

1
@ChamilaWijayarathna, Musisz dołączyć cstdlib
Veridian

103

To rozwiązanie wymaga C ++ 11 (lub 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;
}

Aby uzyskać więcej informacji, zobacz artykuł Johna D. Cooka „Generowanie liczb losowych przy użyciu C ++ TR1” .

Zobacz także „Generowanie liczb losowych” Stroustrupa .


7
Możesz zaktualizować to nowszym dokumentem cppreference , który jest całkiem niezły.
Shafik Yaghmour

10

Powinno to być wydajne, bezpieczne dla wątków i wystarczająco elastyczne do wielu zastosowań:

#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

Jeśli dokładność jest tutaj problemem, możesz utworzyć liczby losowe z dokładniejszą podziałką, losując znaczące bity. Załóżmy, że chcemy mieć podwójną wartość między 0,0 a 1000,0.

Na przykład na MSVC (12 / Win32) RAND_MAX to 32767.

Jeśli użyjesz wspólnego rand()/RAND_MAXschematu, twoje luki będą tak duże jak

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

W przypadku podwójnych zmiennych IEE 754 (53 znaczące bity) i 53-bitowej randomizacji najmniejsza możliwa luka randomizacji dla problemu od 0 do 1000 będzie wynosić

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

a zatem znacznie niższe.

Wadą jest to, że do uzyskania losowej liczby całkowitej (przy założeniu 15-bitowego RNG) potrzebne będą 4 wywołania rand ().

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

Jeśli liczba bitów mantysy lub RNG jest nieznana, w ramach funkcji należy uzyskać odpowiednie wartości.

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

Uwaga: nie wiem, czy liczba bitów dla długości bez znaku (64 bity) jest większa niż liczba bitów podwójnej mantysy (53 bity dla IEE 754) na wszystkich platformach, czy nie. Byłoby prawdopodobnie „sprytne” dołączenie czeku, takiego jak if (sizeof(unsigned long long)*8 > num_mant_bits) ...gdyby tak nie było.


3

Ten fragment pochodzi bezpośrednio z książki Stroustrup The C ++ Programming Language (4. wydanie) , §40.7; wymaga 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;
}

0

coś takiego:

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

2
"(random ()% max_rand)" = "random ()" (tj. 3% 7 = 3). Byłby to zmarnowany etap przetwarzania.
Żak
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.