willekeurige dubbele getallen genereren in c++

Hoe je willekeurige getallen tussen twee doubles genereert in c++ , deze getallen zouden eruit moeten zien als xxxxx,yyyyy .


Antwoord 1, autoriteit 100%

Zo gaat het

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

Vergeet niet om srand() aan te roepen met een juiste seed elke keer dat je programma start.

[Bewerken]
Dit antwoord is verouderd omdat C++ zijn native niet-C-gebaseerde willekeurige bibliotheek heeft (zie het antwoord van Alessandro Jacopsons)
Maar dit geldt nog steeds voor C


Antwoord 2, autoriteit 94%

Deze oplossing vereist C++11 (of 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;
}

Zie voor meer details John D. Cook’s “Willekeurige nummergeneratie met C++ TR1”.

Zie ook Stroustrup’s “Willekeurige nummergeneratie”.


Antwoord 3, autoriteit 10%

Dit moet krachtig, draadveilig en flexibel genoeg zijn voor veel gebruik:

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

Antwoord 4, autoriteit 6%

Als nauwkeurigheid hier een probleem is, kun je willekeurige getallen maken met een fijnere gradatie door de significante bits willekeurig te verdelen.
Laten we aannemen dat we een dubbel willen hebben tussen 0,0 en 1000,0.

Op MSVC (12 / Win32) is RAND_MAX bijvoorbeeld 32767.

Als u het algemene rand()/RAND_MAX-schema gebruikt, zijn uw hiaten zo groot als

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

In het geval van IEE 754 dubbele variabelen (53 significante bits) en 53 bit randomisatie zal de kleinst mogelijke randomisatie gap voor het 0 tot 1000 probleem zijn

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

en dus aanzienlijk lager.

Het nadeel is dat er 4 rand()-aanroepen nodig zijn om het gerandomiseerde integrale getal te verkrijgen (uitgaande van een 15-bits RNG).

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

Als het aantal bits voor de Mantissa of het RNG onbekend is, moeten de respectieve waarden binnen de functie worden verkregen.

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

Opmerking: ik weet niet of het aantal bits voor niet-ondertekende lange lange lange lange lange (64 bit) groter is dan het aantal dubbele Mantissa-bits (53 bit voor IEE 754) op alle platforms of niet.
Het zou waarschijnlijk “Smart” zijn om een ​​cheque als if (sizeof(unsigned long long)*8 > num_mant_bits) ...Als dit niet het geval is.


5, Autoriteit 2%

Voor het genereren van willekeurige nummers kunnen we de methoden gebruiken die onze andere vrienden vertelden. Ik wil hier een heel belangrijk punt toevoegen.

De code die anderen verteld is:

//I have made this as a function that returns the random double value, just copy this
// if you want
double random(){
    return (double)rand() / RAND_MAX; // for generating random points between 0 to 1
}
//now suppose I want any random value between two numbers min and max then I can use this as :
int mynum = min + (max-min)*random();

Maar het probleem met deze code is dat het bevooroordeeld is, ik bedoel dat het geen waarde geeft die gelijk is aan 0 en 1.
Klik hier om de afbeelding te bekijken Deze afbeelding laat zien hoe de geretourneerde waarde is bevooroordeeld Centrum (dwz is in de buurt van waarde één). Om dergelijke voorwaarde te voorkomen, moeten we de voorkeur geven aan de volgende code:

double random(){
        return sqrt((double)rand() / RAND_MAX); // for generating random points between 0 to 1
    }

Reden voor het kiezen van Square Root-functie

De reden om sqrt() te kiezen in plaats van andere functies zoals cbrt() om het naar het uiteinde te leiden, is dat in de eerste hierboven genoemde benadering de gegenereerde punten evenredig waren met R ^ 2 omdat onze willekeur evenredig was met R, waardoor het totale gebied van de cirkel evenredig is met R ^ 2, waardoor ze meer naar het midden zijn geconcentreerd. Door onze willekeurig evenredig te maken met sqrt(R) zouden de punten die over het hele gebied van de cirkel worden gegenereerd evenredig zijn met R, waardoor alle punten uniform door de hele cirkel zouden worden gegenereerd.

Houd er rekening mee dat na het toepassen van sqrt (een punt tussen [0, 1]), het resultaat een waarde zou zijn die groter is dan de oorspronkelijke willekeurige (), waardoor het meer naar het buitenste uiteinde wordt vertekend. Hierdoor wordt het punt uniform gegenereerd over de hele cirkel.

Ik wil @archit91 bedanken voor het delen van deze nuttige informatie over LeetCode in dit artikel


Antwoord 6

Er zijn al zoveel geweldige oplossingen en veel zijn erg elegant. Ik dacht dat ik er nog maar een aan de lijst zou toevoegen. Ik haal referenties rechtstreeks uit het ‘Modern C++ Programming CookBook, 2nd edition’. In het hoofdstuk over generatoren van willekeurige getallen wordt enige nadruk gelegd op hoe belangrijk het is om de generatoren van pseudo-willekeurige getallen goed te initialiseren. Het voegt eraan toe dat de Mersenne twister-engine de neiging heeft om sommige waarden herhaaldelijk te produceren en andere waarden niet op te nemen en daarom geen getallen in een uniforme verdeling te genereren, maar meer als een binomiale of Poisson-verdeling. Het fragment dat ik bijvoeg, doorloopt de stappen van het initialiseren van een generator om pseudo-willekeurige getallen te produceren met een echte uniforme distributie.

auto generate_random_double(double lb, double ub)//lb= lowerbound, ub = upperbound
{
    //produce random #'s to be used as seeding values
    std::random_device rd{};
    //Generate random data for all the internal bits of the engine
    std::array<double, std::mt19937::state_size> seed_data{};
    ranges::generate(seed_data,std::ref(rd));
    //Create an std::seed_seq object from the pseudo random data 
    std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
    //Create an engine object and initialize the bits representing the internal      
    //state of the engine; form example an mt19937 has 19937 bits
    auto eng = std::mt19937{ seq };
    //Create object based on the approprieat distribution based on application   
    //requirments 
    const auto randDouble = std::uniform_real_distribution<>{ lb,ub };
    //return object seeded with the previously initialized object
    return randDouble(eng);
}//end method generate_random_double

Antwoord 7

zoiets als dit:

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

Other episodes