#include <morph/Random.h>
Header file: morph/Random.h. Test and example code: tests/testRandom tests/testRandString
Summary
High quality random number generation (RNG) is important in many scientific simulation projects. <morph/Random.h>
provides a set of random number generation classes. These classes wrap the standard random number generation in the C++ <random>
header to give a convenient interface for the programmer. While it is possible to select different pseudo random number generators, the classes all default to the very acceptable mt19937 Mersenne Twister algorithm (using the 32 bit version for RandUniform
/RandPoisson
and the 64 bit version for RandNormal
and RandLogNormal
).
Intervals
This page uses the common mathematical notation for intervals:
- [a,b) for a semi-closed interval which includes values from and including a up to, but not including b.
- [a,b] for a closed interval which includes both a and b in the interval.
morph::RandUniform
Random number generation from a uniform distribution. Any possible value in the interval is equally likely to be returned. The RandUniform
class is templated and has integer and floating point specializations:
namespace morph {
template <typename T = float, typename E = std::mt19937, bool = std::is_integral<std::decay_t<T>>::value>
class RandUniform {};
// Both integer and floating point specializations are implemented
T
is the type for the generated random numbers and E
is the generator algorithm/engine.
Simplest usage
// Floating point RandUniform defaults to the semi-closed interval [0,1)
morph::RandUniform<float> rng1; // Generate random numbers in float type output in interval [0,1)
float f = rng1.get(); // 0 <= f < 1
// By default, an integer RandUniform provides a number from the closed interval [min, max] for the type
morph::RandUniform<unsigned short> rng2;
unsigned short us = rng2.get(); // 0 <= us <= 65535
// Find the end points of the RNG interval with min() and max():
std::cout << "Integer RNG generates numbers in range " << rng2.min() << " to " << rng2.max() << std::endl;
Setting the interval
You can choose an interval over which random numbers should be generated in the constructor
// Create a generator of integer values in interval [0,10]. The interval type should match
// the RandUniform template type (unsigned int here)
morph::RandUniform<unsigned int> rng (0, 10);
// Create a floating point RNG for the interval [-100, 100)
morph::RandUniform<double> rng (-100.0, 100.0);
Using a fixed seed
To use a fixed seed with the default interval, use a single unsigned int
argument to the constructor:
morph::RandUniform<int> rng (2303); // The first .get() should always return the same number now
To use a fixed seed with a custom interval, it’s the third argument:
// Declaration
RandUniform (T a, T b, unsigned int _seed);
// In use:
morph::RandUniform<int> rng (0, 100, 2303); // Interval [0,100], seed = 2303
Getting arrays of randomly generated values
If you need to obtain a large number of randomly generated values, it is most efficient to get these into an array, rather than using RandUniform::get()
` repeatedly.
morph::RandUniform<double> rng (0.0, 10.0);
// One overload returns std::vector of results
std::vector<double> randoms_in_vector = rng.get (100); // Return a vector with 100 random numbers
// Another places values into an existing std::array
std::array<double, 100> randoms_in_array;
rng.get (randoms_in_array);
Changing the engine
By default the 32 bit mt19937 Mersenne Twister algorithm is used in RandUniform
. To select a different engine, specify it as a second template parameter.
morph::RandUniform<float, std::mt19937_64> rng1; // Use the 64 bit version of mt19937
morph::RandUniform<float, std::minstd_rand> rng2; // Use the linear congruential engine
There are some notes about the different engines that you can use in the comments in morph/Random.h. You can also consult C++ reference material.
One-line RandUniform calls
This is a way to use RandUniform
in your program with a single line of code. It creates one singleton class that manages the memory used by the RandUniform<float>
object and one for RandUniform<double>
and allows you to retrieve random values with morph::randSingle
and morph::randDouble
function calls:
#include <morph/rng.h>
int main() {
float rnum_single = morph::randSingle(); // single precision or...
double rnum_double = morph::randDouble(); // double.
return 0;
}
To enable only randSingle
use #include <morph/rngs.h>
and to enable only randDouble
, use #include <morph/rngd.h>
. There is no equivalent for RandNormal
or any of the other Rand*
classes, but it would not be difficult to copy and adapt rng.h if you need this.
morph::RandNormal and morph::RandLogNormal
Two C++ classes to generate values from either a normal (Gaussian) distribution or a log-normal distribution.
All the examples here show RandNormal
, but you can substitute RandLogNormal
if you want the log-normal distribution to generate your values.
namespace morph {
template <typename T = double, typename E = std::mt19937_64>
class RandNormal { // or class RandLogNormal
T
is the type for the generated random numbers and E
is the generator algorithm/engine.
Simplest usage
To generate values from a normal distribution with mean 0 and standard deviation 1, create the a default RandNormal object:
morph::RandNormal<float> rng;
rng.get(); // Getters are the same across the Rand* classes
Specifying the normal distribution parameters
The mean and standard deviation can be specified in the constructor:
morph::RandNormal<double> rng (1.0, 2.0); // Mean 1, standard deviation 2.
Using a fixed seed
To use a fixed seed with the default interval, use a single unsigned int
argument to the constructor:
morph::RandNormal<double> rng (2303); // The first .get() should always return the same number now
To use a fixed seed with a custom interval, it’s the third argument:
// Declaration
RandNormal (T a, T b, unsigned int _seed);
// In use:
morph::RandNormal<float> rng (2.0f, 3.0f, 2303); // mean 2, std 3, seed = 2303
Getters
The get()
function overloads are the same in all the Rand*
classes, so you can:
T value = rng.get();
// or
std::vector<T> values = rng.get (num);
// or
std::array<T, N> avals;
rng.get (avals);
morph::RandPoisson
A C++ classes to generate values from a normal Poisson distribution.
namespace morph {
template <typename T = int, typename E = std::mt19937>
class RandPoisson
T
is the integral type for the generated random numbers and E
is the generator algorithm/engine.
Simplest usage
To generate values from a Poisson distribution with mean 0, create the a default object:
morph::RandPoisson<int> rng;
rng.get();
Specifying the distribution mean
The mean can be specified in the constructor:
morph::RandPoisson<int> rng (3); // Mean 3
Using a fixed seed
To use a fixed seed with the default interval, use a single unsigned int
argument to the constructor:
morph::RandPoisson<int> rng (2303); // The first .get() should always return the same number now
To use a fixed seed with a custom mean, it’s the second argument:
// Declaration
RandPoisson (T mean, unsigned int _seed);
// In use:
morph::RandPoisson<int> rng (4, 2303); // mean 4, seed = 2303
Getters
The get()
function overloads are the same as for RandUniform
, RandNormal
and RandLogNormal
.
morph::RandString
The RandString
class is a little different from the other Rand*
classes because it uses a morph::RandUniform
member to help it generate character strings. It allows you to generate random characters from different character groups such as morph::CharGroup::AlphaNumeric
or morph::CharGroup::Decimal
. It is a non-templated class:
namespace morph {
class RandString
Simplest usage
To generate 8 HexLowerCase characters:
morph::RandString string_gen; // Default string length 8, default char group HexLowerCase.
std::string randchars = string_gen.get();
You can get any length of string. For the example above, to get another 10 HexLowerCase characters:
std::string morechars = string_gen.get (10); // updates RandString::length to 10 before getting chars
You can also change the character group at runtime:
string_gen.setCharGroup (morph::CharGroup::AlphaNumeric);
Constructors
RandString(); // Default, length set to 8, char group set to HexLowerCase
RandString(const size_t l) // Construct with length set to l
RandString(const size_t l, const morph::CharGroup& _cg) // Length l, character group _cg
The list of possible character groups is given by the CharGroup
declaration:
namespace morph {
enum class CharGroup
{
AlphaNumeric, // 0-9A-Za-z 62 chars
Alpha, // A-Za-z 52 chars
AlphaNumericUpperCase, // 0123456789ABCDEF... ...XYZ 36 chars
AlphaNumericLowerCase, // 0123456789abcdef... ...xyz 36 chars
AlphaUpperCase, // A-Z 26 chars
AlphaLowerCase, // a-z 26 chars
HexUpperCase, // 0123456789ABCDEF 16 chars
HexLowerCase, // 0123456789abcdef 16 chars
Decimal, // 0123456789 10 chars
BinaryTF, // TF 2 chars
Binary // 01 2 chars
};
}