Generowanie liczb losowych

271

Jak wygenerować losowe zmiennoprzecinkowe w C ++?

Myślałem, że mógłbym wziąć liczbę całkowitą i podzielić ją przez coś, czy to wystarczy?

hasen
źródło
2
To zależy raczej od tego, dla czego chcesz numer i od tego, jak losowy. typowo rand () daje 15 bitów losowości, ale zmiennoprzecinkowe mają 23-bitową precyzję, więc pominą niektóre wartości.
Pete Kirkham
1
Zaktualizowałem swoją odpowiedź, aby uwzględnić wszystkie główne dostępne opcje, a mój wybór skoncentrowania się na randomnagłówku dodanym w C ++ 11 jest dodatkowo wzmocniony przez standardowy dokument N3924: Odradzanie rand () w C ++ 14 . rand()W mojej odpowiedzi zawarłem głównie względy historyczne, ale zdałem sobie również sprawę z tego, że starsze aplikacje istnieją.
Shafik Yaghmour,
Moja odpowiedź dotyczy tego, jak unikać uzyskiwania tych samych liczb za każdym razem z <random>nagłówkiem
Andreas DM

Odpowiedzi:

381

rand()może być używany do generowania liczb pseudolosowych w C ++. W połączeniu z RAND_MAXodrobiną matematyki możesz generować losowe liczby w dowolnym wybranym przedziale czasowym. Jest to wystarczające do celów uczenia się i programów zabawek. Jeśli potrzebujesz naprawdę losowych liczb o rozkładzie normalnym, musisz zastosować bardziej zaawansowaną metodę.


To wygeneruje liczbę od 0,0 do 1,0 włącznie.

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

To generuje liczbę od 0,0 do pewnego arbitralne float, X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

To wygeneruje liczbę od dowolnej LOdo dowolnej HI:

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));

Pamiętaj, że rand()funkcja często nie będzie wystarczająca, jeśli potrzebujesz naprawdę losowych liczb.


Przed zadzwonieniem rand()musisz najpierw „zaszczepić” generator liczb losowych, dzwoniąc srand(). Należy to zrobić raz podczas uruchamiania programu - nie raz za każdym razem, gdy dzwonisz rand(). Często odbywa się to w następujący sposób:

srand (static_cast <unsigned> (time(0)));

Aby zadzwonić randlub srandmusisz #include <cstdlib>.

Aby zadzwonić time, musisz #include <ctime>.

John Dibling
źródło
22
Nie zapomnij najpierw wysiać nasion!
Klaim
14
Należy zauważyć, że oba limity są włącznie.
dmckee --- były moderator kociąt
14
Ta odpowiedź jest myląca. Zostało to omówione na Going Native 2013 w zeszłym tygodniu; rand () Uważany za szkodliwy, channel9.msdn.com/Events/GoingNative/2013/ ... zawiera bardzo szczegółowe wyjaśnienia.
Ade Miller,
14
Nie rozumiem, dlaczego tak wiele osób głosowało za odpowiedzią. Jest to matematycznie niepoprawne. RAND_MAX jest bardzo małą liczbą (zwykle 2 ^ 16). Oznacza to, że z 23 bitów zmiennoprzecinkowych tworzysz tylko 15 losowych. Pozostałe będą prawdopodobnie zerowe. Rzeczywiście otrzymasz losowe liczby w jednolitym rozkładzie, ale o niskiej precyzji. Na przykład generator losowy może wygenerować 0,00001 i 0,00002, ale nie może wygenerować 0,000017. Masz więc jednolity rozkład, ale niskiej precyzji (256 razy mniej precyzji niż rzeczywisty zmiennoprzecinkowy).
DanielHsH
10
@DanielHsH: OP zapytał konkretnie, z jaką mechaniką można by korzystać do generowania losowych liczb zmiennoprzecinkowych rand(). To pytanie i moja odpowiedź koncentrowały się na nauce podstaw i nie dotyczyły wysokiego stopnia precyzji. Musisz nauczyć się chodzić, zanim zaczniesz biegać.
John Dibling,
137

C ++ 11 daje wiele nowych opcji random. Artykuł kanoniczny na ten temat to N3551, generowanie liczb losowych w C ++ 11

Aby dowiedzieć się, dlaczego używanie rand()może być problematyczne, zapoznaj się z materiałem prezentacyjnym Rand () „Uważany za szkodliwy” Stephana T. Lavaveja podanym podczas imprezy GoingNative 2013 . Slajdy są w komentarzach, ale tutaj jest bezpośredni link .

Obejmuję również, boosta także używam, randponieważ starszy kod może nadal wymagać jego obsługi.

Poniższy przykład jest oddestylowany ze strony cppreference i używa silnika std :: mersenne_twister_engine i std :: uniform_real_distribution, który generuje liczby w [0,10)przedziale, z innymi silnikami i dystrybucjami skomentowanymi ( zobacz na żywo ):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    //
    // Distribtuions
    //
    std::uniform_real_distribution<> dist(0, 10);
    //std::normal_distribution<> dist(2, 2);
    //std::student_t_distribution<> dist(5);
    //std::poisson_distribution<> dist(2);
    //std::extreme_value_distribution<> dist(0,2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

wynik będzie podobny do następującego:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****

Dane wyjściowe będą się różnić w zależności od wybranej dystrybucji, więc jeśli zdecydujemy się na std :: normal_distribution z wartością 2zarówno średnią, jak i stddev, np. Wynikdist(2, 2) będzie podobny do tego ( zobacz na żywo ):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 

Poniżej znajduje się zmodyfikowana wersja niektórych kodów przedstawionych w N3551( zobacz na żywo ):

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

std::default_random_engine & global_urng( )
{
    static std::default_random_engine u{};
    return u ;
}

void randomize( )
{
    static std::random_device rd{};
    global_urng().seed( rd() );
}

int main( )
{
  // Manufacture a deck of cards:
  using card = int;
  std::array<card,52> deck{};
  std::iota(deck.begin(), deck.end(), 0);

  randomize( ) ;  

  std::shuffle(deck.begin(), deck.end(), global_urng());
  // Display each card in the shuffled deck:
  auto suit = []( card c ) { return "SHDC"[c / 13]; };
  auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };

  for( card c : deck )
      std::cout << ' ' << rank(c) << suit(c);

   std::cout << std::endl;
}

Wyniki będą wyglądać podobnie do:

5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S

Podnieść

Oczywiście Boost.Random jest również zawsze opcją, tutaj używam boost :: random :: uniform_real_distribution :

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::random::mt19937 gen;
    boost::random::uniform_real_distribution<> dist(0, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(gen))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

skraj()

Jeśli musisz użyć rand(), możemy przejść do C FAQ, aby uzyskać wskazówki na temat tego, jak wygenerować zmiennoprzecinkowe liczby losowe? , który w zasadzie daje przykład podobny do tego dla generowania interwału [0,1):

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

i wygenerować liczbę losową z zakresu od [M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
Shafik Yaghmour
źródło
1
czy możesz naprawić swój randMToNpls? albo zauważ, że to, [M,N]albo dodaj + 1.powyższe randZeroToOne. -> pomyśl, jak nazwać to w ten sposób:randMToN(0.0, 1.0);
BeyelerStudios
1
Uważaj również na dzielenie przez zero na (N-M). Dobry sposób radzenia sobie z tym błędem można znaleźć tutaj: stackoverflow.com/questions/33058848/...
Dr Beco
61

Spójrz na Boost.Random . Możesz zrobić coś takiego:

float gen_random_float(float min, float max)
{
    boost::mt19937 rng;
    boost::uniform_real<float> u(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
    return gen();
}

Pobaw się, lepiej lepiej przekazać ten sam obiekt MT19937 zamiast budować nowy za każdym razem, ale mam nadzieję, że masz pomysł.

rlbond
źródło
1
uniform_real używa półotwartego przedziału [min, maks.), co oznacza, że ​​uzyskasz minimalną wartość, ale nigdy nie osiągnie maksymalnej. Jest to coś do rozważenia, chociaż jeśli w jakiś sposób zaokrąglisz, możesz rozwiązać ten problem.
TehWan
20
To jest teraz częścią C ++ 11.
Tomas Andrle
@Wolf w praktycznych zastosowaniach prawdopodobieństwo trafienia dowolnej określonej wartości zmiennoprzecinkowej jest tak niskie, że nie ma znaczenia, czy punkt końcowy zostanie uwzględniony, czy wykluczony. Jeśli trzeba max, ale można użyć otwarty min, można odwrócić interwał prosty sposób: return min + max - gen();.
Mark Ransom
26

W wersji współczesnej c++możesz użyć <random>dołączonego nagłówka c++11.
Aby uzyskać losowe float, możesz użyć std::uniform_real_distribution<>.

Możesz użyć funkcji do wygenerowania liczb, a jeśli nie chcesz, aby liczby były zawsze takie same , ustaw silnik i rozkład static.
Przykład:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

Idealnie jest umieścić go floatw pojemniku, takim jak std::vector:

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

Przykładowe dane wyjściowe:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
Andreas DM
źródło
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1jest technicznie niepoprawny, 1.0 nigdy nie zostanie wygenerowany, patrz 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.
Troyseph
1
To powinna być zaakceptowana odpowiedź, to do cholery 2020.
Alex
25

Wywołaj kod z dwiema floatwartościami, kod działa w dowolnym zakresie.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Ivan Prodanov
źródło
Warto wspomnieć, że jest to potencjalny przypadek użycia fmaf()(lub fma()przeciążenia zmiennoprzecinkowego w C ++) w C99 lub C ++ 11, który może zachować większą precyzję. Jak w, fmaf((float)rand() / RAND_MAX, b - a, a).
Tim Čas,
22

Jeśli używasz C ++, a nie C, pamiętaj, że w raporcie technicznym 1 (TR1) i w wersji roboczej C ++ 0x dodali ułatwienia dla generatora liczb losowych w pliku nagłówkowym, uważam, że jest on identyczny z Boost. Random biblioteka i zdecydowanie bardziej elastyczna i „nowoczesna” niż funkcja biblioteki C, rand.

Ta składnia oferuje możliwość wyboru generatora (takiego jak Mersenne Twister MT19937), a następnie wyboru rozkładu (normalny, bernoulli, dwumianowy itp.).

Składnia jest następująca (bezwstydnie zapożyczony z tej strony ):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;
Stóg
źródło
2
Jest to teraz w C ++ 11, również dist można zainicjalizować wartościami min i max.
Étienne
Wydaje mi się dziwne umieszczanie wartości minimalnej i maksymalnej w inicjalizatorze i podawanie generatora podczas uzyskiwania wartości - wolałbym, gdyby było odwrotnie, no cóż.
yoyo
6

W niektórych systemach (Windows z pamięcią VC, obecnie) RAND_MAXjest absurdalnie mały, tj. mi. tylko 15 bitów. Przy dzieleniu przezRAND_MAX generujesz mantysę 15 bitów zamiast 23 możliwych bitów. To może, ale nie musi stanowić problemu, ale w tym przypadku brakuje niektórych wartości.

Och, właśnie zauważyłem, że był już komentarz do tego problemu. Tak czy inaczej, oto kod, który może rozwiązać ten problem:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Nie przetestowano, ale może działać :-)

Joey
źródło
Co z float r = (float) ((rand () << 9) | rand ()) / RAND_MAX? (również niesprawdzony)
Trap
Argh, przepraszam, dzielenie przez RAND_MAX nigdzie cię nie zabierze ... celem tej sztuczki było posiadanie czegoś większego niż RAND_MAX ... naprawiłem to również dla mnie.
Joey
2
Uważaj przy tworzeniu liczb losowych bez teorii ... kolejne wywołania funkcji rand () mogą nie być całkowicie niezależne. Wskazówka: jeśli jest to liniowy generator kongruencjalny, obserwuj niski bit przy kolejnych połączeniach: zmienia się na 0 i 1.
RBerteig
Wiem. Jednak w przypadku niektórych aplikacji może to wystarczyć. Ale tak, w tym przypadku prawdopodobnie powinieneś użyć więcej niż tylko dwóch połączeń. W tym przypadku nie ma srebrnej kuli, nie można nawet polegać na LCG. Inne PRNG mają słabe wysokie bity. Rozwiązanie doładowania powinno być tutaj najlepsze.
Joey
(nb: Niski bit zwrócony przez Rand w MSVC nie jest najniższym bitem stanu RNG. Dla 100 wywołań rand () otrzymuję następujące: 1100100000111111101010010010010011010101110110110111010011111100100000000010100011011000000100101100011. Java używa 48-bitowego LCG i używa tylko 32 bitów, VC wydaje się zrobić to w podobny sposób)
Joey
4

drand48(3)jest standardowym sposobem POSIX. Glibc udostępnia również wersję wielowejściowy, drand48_r(3).

Funkcja została uznana za przestarzałą w SVID 3, ale nie podano odpowiedniej alternatywy, więc IEEE Std 1003.1-2013 nadal ją zawiera i nie ma żadnych notatek, że w najbliższym czasie będzie działać.

W systemie Windows standardowym sposobem jest CryptGenRandom () .

ivan_pozdeev
źródło
2

Żadna z dotychczasowych odpowiedzi nie była dla mnie satysfakcjonująca, dlatego napisałem nową losową funkcję float. Dokonuje bitowych założeń dotyczących typu danych zmiennoprzecinkowych. Nadal potrzebuje funkcji rand () z co najmniej 15 losowymi bitami.

//Returns a random number in the range [0.0f, 1.0f).  Every
//bit of the mantissa is randomized.
float rnd(void){
  //Generate a random number in the range [0.5f, 1.0f).
  unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
  unsigned short coinFlips;

  //If the coin is tails, return the number, otherwise
  //divide the random number by two by decrementing the
  //exponent and keep going. The exponent starts at 63.
  //Each loop represents 15 random bits, a.k.a. 'coin flips'.
  #define RND_INNER_LOOP() \
    if( coinFlips & 1 ) break; \
    coinFlips >>= 1; \
    ret -= 0x800000
  for(;;){
    coinFlips = rand();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    //At this point, the exponent is 60, 45, 30, 15, or 0.
    //If the exponent is 0, then the number equals 0.0f.
    if( ! (ret & 0x3F800000) ) return 0.0f;
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
  }
  return *((float *)(&ret));
}
iNFiNiTyLoOp
źródło
7
ciekawe podejście, chciałbym wyrazić opinię, ale naprawdę nie rozumiem, co się dzieje
hasen
2

Moim zdaniem powyższa odpowiedź daje trochę „losowych” liczb zmiennoprzecinkowych, ale żadna z nich nie jest naprawdę zmiennoprzecinkowa (tzn. Brakuje im części reprezentacji liczb zmiennoprzecinkowych). Zanim przejdę do mojej implementacji, rzućmy okiem na standardowy format ANSI / IEEE dla pływaków:

| znak (1-bit) | e (8 bitów) | f (23-bitowy) |

liczba reprezentowana przez to słowo to (znak * *) * 2 ^ e * 1.f

zwróć uwagę, że liczba „e” jest liczbą tendencyjną (z odchyleniem 127), a zatem w zakresie od -127 do 126. Najprostszą (a właściwie najbardziej losową) funkcją jest po prostu zapisanie danych losowej liczby int w liczbie zmiennoprzecinkowej, a zatem

int tmp = rand();
float f = (float)*((float*)&tmp);

zwróć uwagę, że jeśli to zrobisz float f = (float)rand();, przekształci liczbę całkowitą na liczbę zmiennoprzecinkową (w ten sposób 10 zmieni się w 10,0).

Więc teraz, jeśli chcesz ograniczyć maksymalną wartość, możesz zrobić coś takiego (nie jestem pewien, czy to działa)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

ale jeśli spojrzysz na strukturę pływaka, zobaczysz, że maksymalna wartość pływaka wynosi (około) 2 ^ 127, co jest znacznie większe niż maksymalna wartość int (2 ^ 32), co wyklucza znaczną część liczby, które mogą być reprezentowane przez liczbę zmiennoprzecinkową. Oto moje końcowe wdrożenie:

/**
 * Function generates a random float using the upper_bound float to determine 
 * the upper bound for the exponent and for the fractional part.
 * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
 * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
 * @param sign_flag if sign_flag = 0 the random number is always positive, if 
 *              sign_flag = 1 then the sign bit is random as well
 * @return a random float
 */
float randf(int min_exp, int max_exp, char sign_flag) {
    assert(min_exp <= max_exp);

    int min_exp_mod = min_exp + 126;

    int sign_mod = sign_flag + 1;
    int frac_mod = (1 << 23);

    int s = rand() % sign_mod;  // note x % 1 = 0
    int e = (rand() % max_exp) + min_exp_mod;
    int f = rand() % frac_mod;

    int tmp = (s << 31) | (e << 23) | f;

    float r = (float)*((float*)(&tmp));

    /** uncomment if you want to see the structure of the float. */
//    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);

    return r;
}

użycie tej funkcji randf(0, 8, 0)zwróci liczbę losową z zakresu od 0,0 do 255,0

użytkownik2546926
źródło
1
masz błąd. rand ()% frac_mod nie będzie działać, ponieważ MAX_RAND jest zwykle niższy niż (1 << 23).
DanielHsH,
Muszę przyznać, że nie znam dokładnego rozmiaru MAX_RAND. Niemniej jednak nadal będzie działać, być może jest to bezużyteczne stwierdzenie, ale nadal będzie działać. 8% 10 = 8, więc to dobrze, ale jeśli MAX_RAND jest zawsze mniejszy niż (1 << 23), możesz go rzeczywiście usunąć.
user2546926,
2
Nie, trochę się mylisz. RandMax wynosi zwykle ~ 65 000. Oznacza to, że z 23 bitów losujesz tylko 15. Pozostałe będą prawdopodobnie zerowe. Rzeczywiście otrzymasz losowe liczby, ale o niskiej precyzji. Na przykład generator losowy może wygenerować 0,001 i 0,002, ale nie może wygenerować 0,0017. Masz więc jednolity rozkład, ale niskiej precyzji (256 razy mniej precyzji niż liczba zmiennoprzecinkowa).
DanielHsH 17.07.13
W tej odpowiedzi są dwa błędy. Naprawianie zakresu wykładniczego: int e = (rand() % (max_exp - min_exp)) + min_exp_mod;i mantysy: int f = (int)(frac_mod * (float)rand() / RAND_MAX);zastępując ich odpowiednie linie powyżej. Zauważ, że błąd mantysy jest poważny: dla RAND_MAXmniejszych 1 << 23losowałbyś tylko mniejsze znaczące bity i otrzymywałeś zero dla najbardziej znaczących bitów przez cały czas!
BeyelerStudios
2

Jeśli wiesz, że twój format zmiennoprzecinkowy to IEEE 754 (prawie wszystkie współczesne procesory, w tym Intel i ARM), możesz zbudować losową liczbę zmiennoprzecinkową z losowej liczby całkowitej, stosując metody bitowe. Należy to wziąć pod uwagę tylko wtedy, gdy nie masz dostępu do C ++ 11 randomlub Boost.Randomoba są znacznie lepsze.

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

Zapewni to lepszą dystrybucję niż ta wykorzystująca podział.

Mark Ransom
źródło
8
Nie jestem pewien, dlaczego mówisz, że dałoby to „lepszą dystrybucję”. W rzeczywistości da to dokładnie taką samą dystrybucję jak just return (float)random23 / (1 << 23). (Tak, właśnie to przetestowałem , modyfikując twoją funkcję random32jako parametr i uruchamiając ją dla wszystkich wartości od zera do (1 << 23)-1. I tak, twoja metoda rzeczywiście daje dokładnie takie same wyniki jak dzielenie przez 1 << 23.)
Ilmari Karonen
1

W przypadku C ++ może generować rzeczywiste liczby zmiennoprzecinkowe w zakresie określonym przez distzmienną

#include <random>  //If it doesnt work then use   #include <tr1/random>
#include <iostream>

using namespace std;

typedef std::tr1::ranlux64_base_01 Myeng; 
typedef std::tr1::normal_distribution<double> Mydist;

int main() { 
       Myeng eng; 
       eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
       Mydist dist(1,10); 

       dist.reset(); // discard any cached values 
       for (int i = 0; i < 10; i++)
       {
           std::cout << "a random value == " << (int)dist(eng) << std::endl; 
       }

       return (0);
}
Marco167
źródło
1
Czy właśnie skopiowałeś i wkleiłeś kod z tej odpowiedzi? stackoverflow.com/a/1118739/1538531
Derek
Właściwie nie. Jestem trochę zaskoczony, widząc, jak wyglądają podobnie! Ale zainicjowałem silnik-generator 1 stycznia 1970 roku.
Marco167,
Słusznie. Zauważyłem, że zainicjowałeś generator do epoki, ale ten kod jest podobny!
Derek
Podanie przykładu TR1 wydaje mi się dziwne. Czy możesz wyjaśnić, w jakich przypadkach ktoś musiałby użyć TR1 zamiast C ++ 11?
Shafik Yaghmour,
0

rand () zwraca wartość int między 0 a RAND_MAX. Aby uzyskać liczbę losową z zakresu od 0,0 do 1,0, najpierw rzutuj int int przez rand () na liczbę zmiennoprzecinkową, a następnie podziel przez RAND_MAX.

James Curran
źródło
0
#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

/* single precision float offers 24bit worth of linear distance from 1.0f to 0.0f */
float getval() {
    /* rand() has min 16bit, but we need a 24bit random number. */
    uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
    /* 5.9604645E-8 is (1f - 0.99999994f), 0.99999994f is the first value less than 1f. */
    return (double)r * 5.9604645E-8;
}

int main()
{
    srand(time(NULL));
...

Nie mogłem opublikować dwóch odpowiedzi, więc oto drugie rozwiązanie. log2 liczb losowych, masywne odchylenie w kierunku 0,0f, ale to naprawdę losowa liczba zmiennoprzecinkowa od 1,0f do 0,0f.

#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

float getval () {
    union UNION {
        uint32_t i;
        float f;
    } r;
    /* 3 because it's 0011, the first bit is the float's sign.
     * Clearing the second bit eliminates values > 1.0f.
     */
    r.i = (rand () & 0xffff) + ((rand () & 0x3fff) << 16);
    return r.f;
}

int main ()
{
    srand (time (NULL));
...
Mike Mestnik
źródło