Generate random numbers in C++ at compile time
I know this question is five years old, and already has an accepted answer. Even so, I would like to add that it certainly is possible to generate random numbers at compile time, with the understanding that you'll get the same sequence of random numbers each time you run the program. To put it simply, if the seed is known at compile time, the compiler is allowed to figure out what random numbers will be output, and just turn the program into "output this sequence of numbers."
Compilers will have limits to how aggressively they optimize, so I can't promise that they will always make this substitution, and I doubt any compiler would be able to make the substitution for something as complex as the Mersenne Twister, but something simpler like linear_congruential_engine
has a chance (also, the only way to be sure that it happened would be to have the compiler output assembly code, and then you look at the assembly code).
I know this is possible because I implemented a random generator modeled after random_device
that used Marsaglia's Xorshift algorithm. Since Marsaglia's paper actually included multiple related algorithms, I had the class take a template parameter to select which shift pattern to use. I wanted to know if the compiler would optimize out the switch
statement I used. I forgot to pass a seed, so the compiler used the default, i.e., the seed was known at compile time. When I looked at the assembly code, not only was the switch
gone, but GCC had optimized the program into "output these three numbers."
The final version of the program listed in the question never actually called the functions to generate the sequence of numbers, and never called the function to seed the generator. This version will do that, but I doubt it will be turned into "print this sequence of random numbers."
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <random>
int get_seed()
{
int hour = std::atoi(__TIME__);
int min = std::atoi(__TIME__ + 3);
int sec = std::atoi(__TIME__ + 6);
return 10000 * hour + 100 * min + sec;
}
int main()
{
// get_seed() returns an int based on __TIME__ (a string literal
// set by the preprocessor), which is known at compile time.
//
// Also, w/r/t the engines in <random>: not setting a seed explicitly
// will use a default seed, which is known at compile time. So if
// you're OK getting the same sequence of numbers for any compilation,
// then "std::mt19937_64 rng;" may be all you need.
std::mt19937_64 rng(get_seed());
std::uniform_real_distribution<double> zero_one(0.0, 1.0);
const int COUNT = 1000;
std::generate_n(std::ostream_iterator<double>(std::cout, "\n"), COUNT,
[&rng, &zero_one]() { return zero_one(rng); });
return 0;
}
There is a research paper on the topic: Random number generator for C++ template metaprograms
containing code snippet for the __TIME__
trick. It also talks about supporting different random number engines and distributions as orthogonal choices.
Only constexpr
functions and constant expressions may be evaluated at compile time. That rules out <chrono>
and <random>
.
What you can do is access the __TIME__
preprocessor macro and define your own PRNG composed of one-line, constexpr
functions.