generate random double numbers in c++
How to generate random numbers between two doubles in c++ , these numbers should 开发者_JAVA技巧look like xxxxx,yyyyy .
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
This solution requires C++11 (or 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;
}
For more details see John D. Cook's "Random number generation using C++ TR1".
See also Stroustrup's "Random number generation".
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';
}
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.
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;
}
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
So many great solutions already and many are very elegant. I just figured I would add another to the list. I am drawing references directly from the 'Modern C++ Programming CookBook, 2nd edition'. In the chapter on random number generators, there is some emphasis on how very important it is to properly initialize the pseudo-random number generators. It adds that the Mersenne twister engine has a bias towards producing some values repeatedly and not including other values therefore not generating numbers in a uniform distribution but more like a binomial or Poisson distribution. The snippet I am including goes through the steps of initializing a generator in order to produce pseudo-random numbers with a true uniform distribution.
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
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);
}
};
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);
}
something like this:
#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;
}
精彩评论