Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generate random double numbers in c++

Tags:

c++

random

How to generate random numbers between two doubles in c++ , these numbers should look like xxxxx,yyyyy .

like image 376
Radi Avatar asked Apr 24 '10 12:04

Radi


People also ask

How do you generate random doubles?

In order to generate Random double type numbers in Java, we use the nextDouble() method of the java. util. Random class. This returns the next random double value between 0.0 (inclusive) and 1.0 (exclusive) from the random generator sequence.

How do you create a random double in C++?

Use std::rand Function to Generate a Random Double in C++ This function generates a pseudo-random integer between ​0​ and RAND_MAX (both included). Since the RAND_MAX value is implementation-dependent, and the guaranteed minimum value is only 32767, generated numbers have constrained randomness.

How does random () work in C?

DESCRIPTION The rand() function returns a pseudo-random integer in the range 0 to RAND_MAX inclusive (i.e., the mathematical range [0, RAND_MAX]). The srand() function sets its argument as the seed for a new sequence of pseudo-random integers to be returned by rand().


7 Answers

Here's how

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

Remember to call srand() with a proper seed each time your program starts.

[Edit] This answer is obsolete since C++ got it's native non-C based random library (see Alessandro Jacopsons answer) But, this still applies to C

like image 57
rep_movsd Avatar answered Oct 04 '22 02:10

rep_movsd


This snippet is straight from Stroustrup's The C++ Programming Language (4th Edition), §40.7; it requires 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;
}
like image 32
Alessandro Jacopson Avatar answered Oct 04 '22 00:10

Alessandro Jacopson


This should be performant, thread-safe and flexible enough for many uses:

#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';
}
like image 21
Galik Avatar answered Oct 04 '22 00:10

Galik


If accuracy is an issue here you can create random numbers with a finer graduation by randomizing the significant bits. Let's assume we want to have a double between 0.0 and 1000.0.

On MSVC (12 / Win32) RAND_MAX is 32767 for example.

If you use the common rand()/RAND_MAX scheme your gaps will be as large as

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

In case of IEE 754 double variables (53 significant bits) and 53 bit randomization the smallest possible randomization gap for the 0 to 1000 problem will be

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

and therefore significantly lower.

The downside is that 4 rand() calls will be needed to obtain the randomized integral number (assuming a 15 bit 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);
}

If the number of bits for the mantissa or the RNG is unknown the respective values need to be obtained within the function.

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

Note: I don't know whether the number of bits for unsigned long long (64 bit) is greater than the number of double mantissa bits (53 bit for IEE 754) on all platforms or not. It would probably be "smart" to include a check like if (sizeof(unsigned long long)*8 > num_mant_bits) ... if this is not the case.

like image 32
Pixelchemist Avatar answered Oct 04 '22 00:10

Pixelchemist


For generating random numbers we can use the methods that our other friends told. I want to add a very important point here.

The code told by others 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();

But the problem with this code is that it is biased, I mean that it is not giving value equally between 0 and 1. Click here to see the image This image shows how the value returned is more biased towards the center (i.e. is near value one). In order to avoid such condition we should prefer the following code:

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

Reason for choosing Square root function

The reason for choosing sqrt() rather than any other functions like cbrt() to bias it towards the outer end is that in the first approach mentioned above, the points generated were proportional to R^2 because our random was proportional to R, thus making points overall area of the circle proportional to R^2 which made them concentrated more towards the center. Making our random proportional to sqrt(R) would make the points generated over all the area of the circle proportional to R which would make all the points generate uniformly throughout the circle.

Note that after applying sqrt (a point between [0, 1]), the result would be a value greater than the original random() thus making it biased more towards the outer end. This makes the point uniformly generated over all of the circle.

I would like to thank @archit91 for sharing this usefull information on LeetCode in this article

like image 28
sachin singh jagawat Avatar answered Oct 04 '22 01:10

sachin singh jagawat


This is similar to my answer above but should work from C++11 and up.

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

/**
 * a function that will generate pseudo random numbers in a normal distribution
 * @param lb  is the lower bound of the distribution (inclusive)
 * @param ub  is the upper bound of the distribution (inclusive)
 * @return  a pseudo random number in the range [lb, ub]
 */
auto generate_random_double(double lb, double ub)
{
    std::random_device rd{};
    std::array<double, std::mt19937::state_size> seed_data{};
    std::generate(seed_data.begin(), seed_data.end(), std::ref(rd));
    std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
    auto eng = std::mt19937{ seq };
    const auto randDouble = std::uniform_real_distribution<>{ lb,ub };
    return std::bind(randDouble, eng);
}

like image 38
Ryan Zurrin Avatar answered Oct 04 '22 02:10

Ryan Zurrin


Here's a self-contained C++ class using C++11. It generates a random double within a half-open interval [low, high) (low <= x < high).

#include <random>

// Returns random double in half-open range [low, high).
class UniformRandomDouble
{
    std::random_device _rd{};
    std::mt19937 _gen{_rd()};
    std::uniform_real_distribution<double> _dist;

    public:

        UniformRandomDouble() {
            set(1.0, 10.0);
        }
        
        UniformRandomDouble(double low, double high) {
            set(low, high);
        }

        // Update the distribution parameters for half-open range [low, high).
        void set(double low, double high) {
            std::uniform_real_distribution<double>::param_type param(low, high);
            _dist.param(param);
        }

        double get() {
            return _dist(_gen);
        }
};
like image 40
stackoverflowuser2010 Avatar answered Oct 04 '22 00:10

stackoverflowuser2010