c++ - Random float number generation

ID : 10324

viewed : 22

Tags : c++randomfloating-pointc++

Top 5 Answer for c++ - Random float number generation

vote vote

98

rand() can be used to generate pseudo-random numbers in C++. In combination with RAND_MAX and a little math, you can generate random numbers in any arbitrary interval you choose. This is sufficient for learning purposes and toy programs. If you need truly random numbers with normal distribution, you'll need to employ a more advanced method.


This will generate a number from 0.0 to 1.0, inclusive.

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

This will generate a number from 0.0 to some arbitrary float, X:

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

This will generate a number from some arbitrary LO to some arbitrary HI:

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

Note that the rand() function will often not be sufficient if you need truly random numbers.


Before calling rand(), you must first "seed" the random number generator by calling srand(). This should be done once during your program's run -- not once every time you call rand(). This is often done like this:

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

In order to call rand or srand you must #include <cstdlib>.

In order to call time, you must #include <ctime>.

vote vote

87

C++11 gives you a lot of new options with random. The canonical paper on this topic would be N3551, Random Number Generation in C++11

To see why using rand() can be problematic see the rand() Considered Harmful presentation material by Stephan T. Lavavej given during the GoingNative 2013 event. The slides are in the comments but here is a direct link.

I also cover boost as well as using rand since legacy code may still require its support.

The example below is distilled from the cppreference site and uses the std::mersenne_twister_engine engine and the std::uniform_real_distribution which generates numbers in the [0,10) interval, with other engines and distributions commented out (see it live):

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

output will be similar to the following:

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

The output will vary depending on which distribution you choose, so if we decided to go with std::normal_distribution with a value of 2 for both mean and stddev e.g. dist(2, 2) instead the output would be similar to this (see it live):

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

The following is a modified version of some of the code presented in N3551 (see it live) :

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

Results will look similar to:

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

Boost

Of course Boost.Random is always an option as well, here I am using 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';     } } 

rand()

If you must use rand() then we can go to the C FAQ for a guides on How can I generate floating-point random numbers? , which basically gives an example similar to this for generating an on the interval [0,1):

#include <stdlib.h>  double randZeroToOne() {     return rand() / (RAND_MAX + 1.); } 

and to generate a random number in the range from [M,N):

double randMToN(double M, double N) {     return M + (rand() / ( RAND_MAX / (N-M) ) ) ;   } 
vote vote

76

Take a look at Boost.Random. You could do something like this:

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

Play around, you might do better passing the same mt19937 object around instead of constructing a new one every time, but hopefully you get the idea.

vote vote

68

In modern c++ you may use the <random> header that came with c++11.
To get random float's you can use std::uniform_real_distribution<>.

You can use a function to generate the numbers and if you don't want the numbers to be the same all the time, set the engine and distribution to be static.
Example:

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

It's ideal to place the float's in a container such as 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 << " "; } 

Example output:

0.0518757 0.969106 0.0985112 0.0895674 0.895542 
vote vote

51

Call the code with two float values, the code works in any range.

float rand_FloatRange(float a, float b) {     return ((b - a) * ((float)rand() / RAND_MAX)) + a; } 

Top 3 video Explaining c++ - Random float number generation

Related QUESTION?