C++ random number generation implementation code

  • 2020-08-22 22:18:51
  • OfStack

C style

The tools C provides for random Numbers are rand, srand, and RAND_MAX, as defined in < stdlib.h > In the.

srand sets the seed for rand, which if not set is equivalent to calling srand(1). rand generates pseudo-random Numbers ranging from 0 to RAND_MAX, RAND_MAX is at least 32767, which is 32767 in both MSVC and GCC.

Pseudo-random Numbers are seemingly random, but they are actually quite regular. For the same seed value, rand produces exactly the same sequence, which means that no matter what number you give srand1, running the program multiple times will produce the same result -- unless you give srand a different number, such as time. < time.h > The time function returns the system time represented by an integer and can be used to set the seed.

If we only need random Numbers from 0 to 9, we can return rand % 10. If it's 42 to 233, you could write rand() % 192 + 42. The random function below encapsulates this work. Note that the distribution of random Numbers is uniform only if ES39en-ES40en + 1 is much less than or divisible by RAND_MAX.


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int random(int a, int b)
{
  return rand() % (b - a + 1) + a;
}

int main()
{
  srand(time(NULL));
  printf("RAND_MAX = %d\n", RAND_MAX);
  for (int i = 0; i < 10; i++)
    printf("%d ", rand());
  printf("\n");
  int count[10] = {0};
  for (int i = 0; i < 10000; i++)
    count[random(0, 9)]++;
  for (int i = 0; i < 10; i++)
  {
    printf("%d: ", i);
    for (int j = 0; j < count[i] / 10; j++)
      printf("*");
    printf("\n");
  }
}

C + + style

Starting from C++11, the C++ standard specifies random number facilities, including uniform random bit generators (Uniform random bit generators, URBG) and random number distribution, etc., which are defined in < random > In the.

URBG is divided into four categories: random number engine, engine adapter, preset random number generator, and non-deterministic random number generator. The latter two are usually sufficient.

The standard specifies three random number engines:

Linear congruence linear_congruential_engine (LCG), less time and space consumption; Mason rotates mersenne_twister_engine (MT), which takes up more memory (it can be ignored on PC) and requires a large amount of calculation. Carry subtraction (belonging to the lagged Fibonacci generator, LFG) subtract_with_carry_engine, a compromise between performance and effect.

Each random number engine needs a seed, and all generated are pseudorandom Numbers.

The engine adapter can set 1 random number engine:

discard_block_engine selects a number from a series of pseudo-random Numbers; independent_bits_engine compacts pseudorandom Numbers with more bits into ones with fewer bits; shuffle_order_engine rearranges a series of pseudo-random Numbers.

Nesting dolls are templates, and in theory you could also use adapters to nest adapters, though CPU might have a problem with that.

How to take template parameters of random number engine? The standard defines a number of random number engines that mathematicians have found to work well: LCG minstd_rand0, minstd_rand, knuth_b; MT mt19937, mt19937_64; LFG ranlux24_base, ranlux48_base, ranlux24, ranlux48 If you still don't know what to do, use default_random_engine. The developers of the compiler have chosen what they think is best for you, mt19937 in MSVC and minstd_rand0 in GCC.

All of the above tools generate pseudo-random Numbers, and the standard also defines a true random number engine, random_device, although the standard also allows it to be pseudo-random. It works best when it is truly random, but performance drops dramatically after multiple calls and is usually used only to generate seeds for the pseudo-random number engine.

The random number generator types both define static methods min and max, which return a range of generated random Numbers, and the no-argument function call operator operator(), which returns a random number.


#include <iostream>
#include <random>

int main()
{
  auto engine = std::default_random_engine(std::random_device()());
  std::cout << "min = " << engine.min() << "; max = " << engine.max() << std::endl;
  std::cout << "random numbers: ";
  for (int i = 0; i != 10; ++i)
    std::cout << engine() << ' ';
  std::cout << std::endl;
}

In most cases we do not need integers in the min to max range, but 1 integer or real number with definite distribution. The standard specifies a lot of random number distribution types, which I'm not good at math and don't understand very well.

Uniform distribution uniform_int_distribution, uniform_real_distribution; Bernoulli distributions bernoulli_distribution, binomial_distribution, negative_binomial_distribution, geometric_distribution; Poisson distributions poisson_distribution, exponential_distribution, gamma_distribution, weibull_distribution, extreme_value_distribution; Normally distributed normal_distribution, lognormal_distribution, chi_squared_distribution, cauchy_distribution, fisher_f_distribution, student_t_distribution, lognormal_distribution, ES167en, chi_squared_distribution, cauchy_distribution, fisher_f_distribution, student_t_distribution.

The sampling distribution of discrete_distribution, piecewise_constant_distribution, piecewise_linear_distribution.

The parameters passed in when constructing a distribution instance. Call operator() to get the result with a random number engine.


#include <iostream>
#include <random>
#include <string>

int main()
{
  auto engine = std::default_random_engine(std::random_device()());
  std::uniform_int_distribution<int> uniform(0, 9);
  int count[10] = {0};
  for (int i = 0; i != 10000; ++i)
    ++count[uniform(engine)];
  for (int i = 0; i != 10; ++i)
    std::cout << i << ": " << std::string(count[i] / 10, '*') << std::endl;
}

Note that the uniform_int_distribution constructor takes a closed interval as an argument, unlike the STL habit of closing left and opening right.


Related articles: