Random numbers pass through random number engine class and random number distribution class.

The engine class can generate unsigned random number sequences; The distribution class uses an engine class to generate random numbers of a specified type, within a given range and subject to a specific probability distribution.

They are defined in the header file random.

Random number engine:

Random number engines are function object classes that define a calling operator that does not accept parameters and returns a random unsigned integer.

Upper Code:

default_random_engine e;//Generate random unsigned number (original random number) int i = 100; for (int i = 0; i < 10; i++) { cout << e( ) << endl;//Call object e to generate 10 random numbers }

Above program output:

The following C++ primer:

Distribution type:

uniform_int_distribution<unsigned> u(1, 100);//Generates a uniformly distributed random number between 1 and 100 inclusive default_random_engine e;//Generate random unsigned number (original random number) for (int i = 0; i < 100; i++) { cout << u(e) << endl;//Using u as a random number source }

The distribution type is also a function object class. It takes a random number engine as a parameter.

What we pass to the distribution object is the engine object itself. Cannot be written as: u (e())

Random number generator refers to the combination of distribution object and engine object.

cout << e.min() << " " << e.max() << endl;//Gets the range of the random number engine

The code we wrote above generates a random number once, and the second generation will be the same, which can not achieve the real random number we want.

We can define the engine and distribution objects as static and keep them in state:

#include <iostream> #include<random> using namespace std; #include<vector> static default_random_engine e; static uniform_int_distribution<unsigned> u(1, 100); vector<unsigned> doo() { vector<unsigned> ret; for (int i = 0; i < 10; i++) { ret.push_back(u(e));//Add element to container } for (auto i : ret)//Utilization range for output { cout << i<<" "; } return ret; } int main() { doo(); //13 3 35 86 5 92 30 86 99 4 cout << endl; doo(); //36 66 41 27 40 21 20 5 98 7 cout << '\n'; doo();// 10 10 44 40 47 27 37 54 61 72 system("pause"); return 0; }

A given random number generator will always generate the same random number sequence. We can realize the real random number by setting the seed of random number generator.

Each run of the program will generate different random results, and we can achieve this by providing a seed.

There are two ways to seed the engine: provide the seed when creating the engine object, or call the seed member of the engine.

default_random_engine e1;//Use default seed values default_random_engine e2(32767);//Given seed value default_random_engine e3; for (int i = 0; i < 10; i++) { cout << e1() <<" "; } cout << endl; for (int i = 0; i < 10; i++) { cout << e2() << " "; } cout << endl; e3.seed(32767);//Call seed to set a new seed value for (int i = 0; i < 10; i++) { cout << e3() << " "; }

In the above code, both e1 and e3 use the default seed value, and their two generated random number sequences will be the same. e2 is given by ourselves. It is different from e1 and e3 and seed values, because some random number sequences generated by e2 will not be the same as the other two. Later, we reset a seed value for e3 by calling the seed function. Like e2, e2 and e3 generate the same random number sequence.

Selecting a good seed is extremely difficult: the most common method is to call the system function time, which is defined in the header file ctime. It returns the number of seconds from a specific time to the current time.

default_random_engine e2(time(0));//Given seed value uniform_int_distribution<int> u(0, 100); cout << endl; for (int i = 0; i < 10; i++) { cout <<u(e2) << " ";//The result of the second call will almost always be different }

Time returns the time in seconds, so this method is only applicable when the interval between seed generation is seconds or more.

Generate random floating point numbers:

We define a uniform_real_distribution Type, let the standard library handle the mapping from random numbers to random floating-point numbers.

default_random_engine e2(time(0));//Given seed value uniform_real_distribution<float> u(0, 1); for (int i = 0; i < 10; i++) { cout <<u(e2) << " ";//Each call has a different floating point number }

Operation of distribution type:

All distribution types are templates with a single template type parameter. Each distribution template has a default template argument.

uniform_real_distribution < > u1(0, 1); //An empty tip indicates that we want to use the default result type and generate a double value by default uniform_int_distribution <> u2(0, 100); // An unsigned value is generated by default

Generate non uniformly distributed random numbers:

normal_distribution generates floating-point values.

default_random_engine e2(time(0));//Given seed value normal_distribution<> n(10, 1.3); for (int i = 0; i < 10; i++) { cout <<lround(n(e2)) << " ";//The lround function rounds a floating-point number to the nearest integer. It is defined in the header file cmath }

bernoulli_distribution class:

It is a normal class and does not accept template parameters. It always returns a bool value, and the probability of returning true is a constant, which is 0.5 by default;

default_random_engine e2(time(0));//Given seed value bernoulli_distribution b; for (int i = 0; i < 10; i++) { cout <<b(e2) << " ";//It returns true and false the same number of times, because the default probability is the same }

The reason for using it is that it allows us to adjust the random probability:

bernoulli_distribution b; //The default is 50 / 50 chance bernoulli_distribution b(.55);//Representative procedures have 55 / 45 opportunities

The engine returns the same sequence of random numbers, so we must declare the engine object outside the loop. Otherwise, a new engine will be created in the second cycle, so that the same value will be generated every time. The distribution object should also be outside the cycle to maintain its state.

If you are interested in other extensions, you can read them yourself (from the book C++ primer):